Spatial data brings a whole set of new problems with it. A point of particular divergence from our regression models, is brought on by the fact that spatial data is often autocorrelated in the random component. That means that nearby errors are often correlated, and violates one of our core assumptions of regression (about the error terms being independent from one another). We need to adjust our models to account for this problem.

With spatial data we are often interested in asking questions about things like:

R has a whole suite of tools for dealing with spatial data. And the visualisation capabilities in particular are very nicely set up. Let’s spend a little bit of time looking at mapping before we move onto generating some statistical models for our data.

If you really want to find out about how to deal with spatial data in R, then this is a great site, full of some lovely tutorials on everything you are likely to want to know: https://data.cdrc.ac.uk/tutorial/an-introduction-to-spatial-data-analysis-and-visualisation-in-r

I definitely recommend this site! You will need to create an account and log in, but it is definitely worth your while. It has very nice workbooks on Point mapping, kernel smoothing, spatial autocorrelation… almost everything you are likely to know. I have taken a lot of what follows from that site, but this workbook will only be scratching the surface of what is there! (Albeit in one relatively quick to work through workbook as opposed to the 12 Practicals that you will find in that site!)

Mapping

When we are dealing with spatial data, we can often end up with a number of different types of data and these can be stored in quite complex datatypes. For example, maps often include:

The sp package is a standard way of dealing with spatial data (stored as objects of type Spatial Polygons). Many packages depend upon it, so it is worth learning about if you are planning to do anything with spatial data.

Often we will get information about spatial objects (i.e. maps) from what is called an OGR data source, which is something that has been constructed according to the Geospatial Data Abstraction Library (GDAL), which is really just a data standard for geospatial data (https://en.wikipedia.org/wiki/GDAL).

R has some pretty good tools for dealing with this stuff. In particular, the readOGR() function in the rgdal package, can be used to read in OGR data. Let’s load it:

library(sp)
library(rgdal)
rgdal: version: 1.2-12, (SVN revision 681)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.1.3, released 2017/20/01
 Path to GDAL shared files: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/rgdal/gdal
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/rgdal/proj
 Linking to sp version: 1.2-5 

We can use readOGR to load up the OGR files that have been made available here: https://data.cdrc.ac.uk/dataset/aa5491c9-cbac-4026-97c9-f9168462f4ac/resource/f8ecc2bc-5313-468d-9653-11f0fd752a7d/download/camdenoa11.zip

Make sure that you download them now, and move them to the directory where you are running your code! (i.e. the pathname might not work!) Have a look at the files - they should look like this:

R knows how to load them all if you specify the path name (“Cambden” for me - I have them in a folder) and the name of the file (i.e. the bit out the front without the filename extension.)

Output.Areas<- readOGR("Camden","Camden_oa11")
OGR data source with driver: ESRI Shapefile 
Source: "Camden", layer: "Camden_oa11"
with 749 features
It has 1 fields

Remember to run ?readOGR to find out more about this function (and the OGR format).

You could look at the structure this map using str(Output.Areas) but its REALLY long! I do recommend you examine the structure of this beasty at least once to get a feeling for what is going on in it. Also - beware - the actual data object itself is even longer! (It takes a lot of information to make a map!) Let’s just look at the head of this data for now

head(Output.Areas)

Hmmmm… doesn’t tell us much ;) you had better explore it in your console (but I am not going to do that here because it will make us all do too much scrolling to get past it).

The weird structure you get occurs because sp objects are stored as S4 objects in R. This is a specific object oriented data format, which is quite complex. You can find out more about all of this in this data camp course https://www.datacamp.com/courses/working-with-geospatial-data-in-r (which is quite good! It is definitely worth your while learning about S4 objects in R, and this is a good way to do it.)

Ok… this thing is of class “SpatialPolygonsDataFrame”. That is a complex beast! (Try running ?SpatialPolygonsDataFrame to find out a bit more about them.) A cool thing about these objects, is that they have a nice handy plot method:

plot(Output.Areas)

Its a map of Cambden! (I guess we should have expected that given that the files are called Cambden_* :| - have a look here if you don’t believe me: https://en.wikipedia.org/wiki/London_Borough_of_Camden).

If you want to find some Australian GIS data then you could try these sites:
- http://www.naturalearthdata.com/downloads/
- http://openstreetmapdata.com/data

Ok… so we have our map. What can we do with it? Well… if we had some data then we could join it to our map… Then we could do lots of cool things ;)

Luckily the same site makes census data for the UK available in an easy to use form. You can download it here: https://data.cdrc.ac.uk/dataset/aa5491c9-cbac-4026-97c9-f9168462f4ac/resource/27949d58-8d9b-43b0-b0dd-dfbe47609cbf/download/practicaldata.csv (don’t forget to put it in the right place so that R can find it):

Census.Data <-read.csv("practicaldata.csv")

(Have a look a the data! What is in there?)

Ok. How do we join it? We use a merge function that comes with the sp package:

OA.Census <- merge(Output.Areas, Census.Data, by.x="OA11CD", by.y="OA")

(Make sure you look up what I did there using the helpfile… in particular - can you work out what is going on with those by.x and by.y options?)

Ok… no errors so it looks like the data merged properly. Now what do we have?

head(OA.Census)
An object of class "SpatialPolygonsDataFrame"
Slot "data":
       OA11CD White_British Low_Occupancy Unemployed Qualification
397 E00004527      48.29060     12.745098   7.511737      35.80786
395 E00004525      40.94488     16.806723   5.990783      42.41071
392 E00004522      44.16244      8.547009   2.116402      56.47668
160 E00004287      31.86813     12.612613   3.286385      67.85714
80  E00004206      56.45161     19.685039   7.983193      31.74603
74  E00004200      39.91935     11.764706   3.524229      57.20339

Slot "polygons":
[[1]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 530490.9 181273.3

Slot "area":
[1] 44544.86

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
           [,1]     [,2]
  [1,] 530648.4 181230.2
  [2,] 530648.0 181228.8
  [3,] 530646.6 181223.8
  [4,] 530646.0 181222.2
  [5,] 530643.1 181214.4
  [6,] 530642.2 181212.1
  [7,] 530640.7 181208.2
  [8,] 530639.9 181206.3
  [9,] 530637.0 181204.3
 [10,] 530635.6 181203.4
 [11,] 530634.9 181202.9
 [12,] 530631.9 181201.1
 [13,] 530631.2 181200.6
 [14,] 530609.2 181190.4
 [15,] 530601.3 181187.4
 [16,] 530601.2 181187.4
 [17,] 530596.8 181185.8
 [18,] 530584.2 181181.1
 [19,] 530567.7 181183.0
 [20,] 530564.7 181183.3
 [21,] 530564.1 181183.4
 [22,] 530559.2 181184.0
 [23,] 530556.0 181184.7
 [24,] 530540.7 181188.1
 [25,] 530540.5 181188.2
 [26,] 530519.1 181193.0
 [27,] 530490.9 181199.3
 [28,] 530484.5 181200.7
 [29,] 530483.7 181200.9
 [30,] 530469.9 181204.0
 [31,] 530468.5 181204.3
 [32,] 530466.4 181204.8
 [33,] 530460.4 181206.2
 [34,] 530454.8 181207.4
 [35,] 530447.6 181209.0
 [36,] 530422.1 181214.8
 [37,] 530421.8 181214.8
 [38,] 530421.5 181214.9
 [39,] 530420.9 181213.9
 [40,] 530420.3 181213.0
 [41,] 530416.6 181207.0
 [42,] 530412.9 181200.9
 [43,] 530407.6 181192.3
 [44,] 530406.5 181190.5
 [45,] 530406.2 181190.0
 [46,] 530404.3 181191.8
 [47,] 530400.9 181195.1
 [48,] 530399.9 181196.1
 [49,] 530398.2 181197.7
 [50,] 530390.8 181204.7
 [51,] 530382.5 181212.7
 [52,] 530381.3 181213.9
 [53,] 530378.1 181216.9
 [54,] 530370.0 181224.7
 [55,] 530356.3 181237.7
 [56,] 530354.7 181239.3
 [57,] 530347.6 181246.0
 [58,] 530347.3 181245.7
 [59,] 530328.3 181224.8
 [60,] 530324.0 181220.1
 [61,] 530320.0 181215.8
 [62,] 530319.5 181215.2
 [63,] 530310.2 181205.0
 [64,] 530308.7 181203.3
 [65,] 530307.0 181205.0
 [66,] 530304.0 181204.0
 [67,] 530300.8 181200.7
 [68,] 530287.7 181208.2
 [69,] 530276.8 181223.2
 [70,] 530276.7 181223.3
 [71,] 530276.8 181224.2
 [72,] 530276.8 181224.2
 [73,] 530280.5 181230.4
 [74,] 530292.0 181241.4
 [75,] 530303.0 181251.9
 [76,] 530306.6 181255.3
 [77,] 530311.5 181260.0
 [78,] 530311.5 181260.1
 [79,] 530323.1 181271.1
 [80,] 530324.0 181272.0
 [81,] 530319.0 181277.0
 [82,] 530318.2 181277.8
 [83,] 530317.1 181277.7
 [84,] 530315.0 181280.0
 [85,] 530315.2 181280.2
 [86,] 530315.5 181280.5
 [87,] 530313.0 181283.0
 [88,] 530321.0 181291.4
 [89,] 530326.5 181297.2
 [90,] 530327.9 181298.7
 [91,] 530344.8 181316.5
 [92,] 530346.0 181317.6
 [93,] 530349.1 181321.0
 [94,] 530352.0 181324.0
 [95,] 530356.9 181328.4
 [96,] 530359.6 181330.8
 [97,] 530363.3 181336.6
 [98,] 530365.3 181335.5
 [99,] 530368.1 181333.8
[100,] 530366.0 181332.0
[101,] 530364.6 181330.6
[102,] 530350.4 181316.1
[103,] 530349.6 181315.3
[104,] 530349.7 181314.9
[105,] 530350.8 181306.2
[106,] 530371.9 181294.7
[107,] 530371.9 181294.7
[108,] 530377.8 181270.7
[109,] 530378.2 181269.2
[110,] 530377.9 181268.2
[111,] 530376.3 181260.9
[112,] 530382.1 181258.2
[113,] 530383.1 181256.8
[114,] 530383.9 181258.0
[115,] 530386.8 181262.3
[116,] 530397.0 181277.0
[117,] 530399.4 181280.4
[118,] 530405.7 181289.3
[119,] 530406.2 181290.0
[120,] 530409.2 181294.2
[121,] 530414.0 181301.0
[122,] 530425.1 181315.8
[123,] 530427.3 181318.8
[124,] 530427.0 181325.9
[125,] 530419.1 181330.0
[126,] 530416.5 181331.4
[127,] 530416.3 181331.5
[128,] 530411.7 181372.3
[129,] 530411.7 181372.6
[130,] 530412.5 181374.2
[131,] 530412.7 181374.3
[132,] 530413.3 181373.7
[133,] 530413.9 181374.2
[134,] 530460.0 181364.5
[135,] 530460.2 181364.2
[136,] 530465.8 181365.2
[137,] 530466.8 181365.4
[138,] 530475.0 181374.0
[139,] 530475.0 181374.0
[140,] 530475.4 181373.5
[141,] 530477.3 181370.9
[142,] 530478.0 181370.0
[143,] 530478.1 181370.1
[144,] 530478.3 181370.2
[145,] 530484.1 181374.8
[146,] 530491.3 181380.4
[147,] 530488.1 181374.8
[148,] 530489.0 181374.1
[149,] 530493.5 181370.7
[150,] 530521.2 181350.1
[151,] 530523.0 181352.0
[152,] 530564.6 181389.7
[153,] 530565.0 181390.0
[154,] 530568.0 181393.0
[155,] 530569.2 181393.5
[156,] 530569.7 181393.7
[157,] 530573.0 181395.0
[158,] 530576.0 181388.8
[159,] 530585.0 181370.0
[160,] 530587.3 181364.9
[161,] 530591.6 181357.9
[162,] 530591.0 181356.8
[163,] 530601.4 181334.0
[164,] 530607.3 181321.0
[165,] 530610.6 181313.6
[166,] 530612.7 181309.1
[167,] 530613.4 181307.6
[168,] 530645.0 181238.0
[169,] 530648.4 181230.2



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 530490.9 181273.3

Slot "ID":
[1] "0"

Slot "area":
[1] 44544.86


[[2]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 530503.0 181445.9

Slot "area":
[1] 24538.26

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
           [,1]     [,2]
  [1,] 530511.3 181531.2
  [2,] 530511.3 181531.1
  [3,] 530512.0 181528.9
  [4,] 530512.2 181528.1
  [5,] 530511.1 181527.7
  [6,] 530517.1 181509.1
  [7,] 530517.2 181508.6
  [8,] 530518.3 181505.1
  [9,] 530520.0 181500.0
 [10,] 530520.7 181498.6
 [11,] 530523.0 181494.0
 [12,] 530527.0 181492.0
 [13,] 530530.0 181489.0
 [14,] 530531.3 181486.2
 [15,] 530535.0 181478.0
 [16,] 530536.6 181474.7
 [17,] 530546.3 181454.2
 [18,] 530554.8 181436.3
 [19,] 530578.9 181456.1
 [20,] 530581.0 181457.9
 [21,] 530599.1 181464.2
 [22,] 530599.6 181464.3
 [23,] 530615.1 181455.4
 [24,] 530624.5 181450.0
 [25,] 530625.0 181449.0
 [26,] 530625.7 181449.3
 [27,] 530652.0 181460.0
 [28,] 530660.2 181463.7
 [29,] 530659.3 181430.0
 [30,] 530660.2 181427.4
 [31,] 530641.0 181420.0
 [32,] 530638.0 181423.0
 [33,] 530636.0 181423.0
 [34,] 530635.0 181423.0
 [35,] 530631.0 181423.0
 [36,] 530621.1 181418.1
 [37,] 530617.6 181416.3
 [38,] 530595.0 181405.0
 [39,] 530574.5 181395.7
 [40,] 530573.0 181395.0
 [41,] 530569.7 181393.7
 [42,] 530569.2 181393.5
 [43,] 530568.0 181393.0
 [44,] 530565.0 181390.0
 [45,] 530564.6 181389.7
 [46,] 530523.0 181352.0
 [47,] 530521.2 181350.1
 [48,] 530493.5 181370.7
 [49,] 530489.0 181374.1
 [50,] 530488.1 181374.8
 [51,] 530491.3 181380.4
 [52,] 530484.1 181374.8
 [53,] 530478.3 181370.2
 [54,] 530478.1 181370.1
 [55,] 530478.0 181370.0
 [56,] 530477.3 181370.9
 [57,] 530475.4 181373.5
 [58,] 530475.0 181374.0
 [59,] 530475.0 181374.0
 [60,] 530466.8 181365.4
 [61,] 530465.8 181365.2
 [62,] 530460.2 181364.2
 [63,] 530460.0 181364.5
 [64,] 530413.9 181374.2
 [65,] 530423.6 181382.8
 [66,] 530430.1 181388.6
 [67,] 530436.7 181394.3
 [68,] 530450.8 181406.8
 [69,] 530450.0 181408.0
 [70,] 530448.0 181411.0
 [71,] 530445.0 181417.0
 [72,] 530443.7 181420.2
 [73,] 530437.8 181435.2
 [74,] 530430.7 181453.0
 [75,] 530422.8 181472.9
 [76,] 530419.6 181480.8
 [77,] 530413.6 181496.1
 [78,] 530412.7 181498.2
 [79,] 530412.0 181500.0
 [80,] 530410.6 181501.4
 [81,] 530410.2 181501.8
 [82,] 530410.0 181502.0
 [83,] 530402.0 181500.0
 [84,] 530380.2 181492.4
 [85,] 530378.1 181495.4
 [86,] 530384.2 181518.4
 [87,] 530390.5 181527.1
 [88,] 530392.7 181529.4
 [89,] 530395.6 181532.4
 [90,] 530399.8 181536.6
 [91,] 530420.7 181558.0
 [92,] 530421.0 181558.4
 [93,] 530424.7 181553.2
 [94,] 530447.1 181521.9
 [95,] 530447.1 181521.8
 [96,] 530452.0 181515.0
 [97,] 530454.0 181516.0
 [98,] 530461.1 181517.5
 [99,] 530469.1 181519.3
[100,] 530480.1 181521.7
[101,] 530484.0 181522.5
[102,] 530488.0 181523.4
[103,] 530500.0 181526.0
[104,] 530505.7 181529.5
[105,] 530508.0 181531.0
[106,] 530510.0 181531.0
[107,] 530511.0 181531.1
[108,] 530511.3 181531.2



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 530503.0 181445.9

Slot "ID":
[1] "1"

Slot "area":
[1] 24538.26


[[3]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 530039.1 181373.1

Slot "area":
[1] 47972.09

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
           [,1]     [,2]
  [1,] 530207.0 181434.0
  [2,] 530209.6 181427.9
  [3,] 530219.1 181405.3
  [4,] 530227.1 181386.5
  [5,] 530231.5 181375.9
  [6,] 530234.0 181370.0
  [7,] 530234.5 181369.5
  [8,] 530234.0 181369.0
  [9,] 530230.1 181367.1
 [10,] 530230.0 181367.0
 [11,] 530222.2 181362.4
 [12,] 530218.0 181360.0
 [13,] 530196.8 181350.7
 [14,] 530193.0 181349.0
 [15,] 530191.9 181348.6
 [16,] 530188.2 181347.0
 [17,] 530178.6 181343.1
 [18,] 530166.0 181338.0
 [19,] 530149.2 181331.3
 [20,] 530136.7 181326.3
 [21,] 530126.0 181322.0
 [22,] 530123.2 181321.0
 [23,] 530112.0 181317.0
 [24,] 530107.6 181315.6
 [25,] 530092.7 181311.0
 [26,] 530087.6 181309.4
 [27,] 530080.0 181307.0
 [28,] 530073.0 181305.0
 [29,] 530065.0 181302.9
 [30,] 530054.5 181300.2
 [31,] 530034.0 181295.0
 [32,] 530031.0 181294.0
 [33,] 530030.5 181291.0
 [34,] 530029.4 181285.3
 [35,] 530027.4 181274.3
 [36,] 530016.0 181276.9
 [37,] 530012.2 181272.6
 [38,] 530012.0 181272.6
 [39,] 530012.0 181272.6
 [40,] 529971.0 181238.8
 [41,] 529956.3 181243.1
 [42,] 529957.7 181268.6
 [43,] 529958.1 181275.0
 [44,] 529965.6 181289.2
 [45,] 529960.0 181289.0
 [46,] 529958.1 181289.0
 [47,] 529953.0 181289.0
 [48,] 529948.0 181290.0
 [49,] 529940.0 181292.0
 [50,] 529936.0 181288.8
 [51,] 529935.7 181288.6
 [52,] 529920.9 181276.9
 [53,] 529911.8 181269.7
 [54,] 529906.1 181265.2
 [55,] 529893.4 181255.2
 [56,] 529890.3 181260.8
 [57,] 529885.9 181268.7
 [58,] 529880.3 181281.6
 [59,] 529864.3 181318.3
 [60,] 529863.2 181320.8
 [61,] 529862.1 181323.2
 [62,] 529860.9 181326.0
 [63,] 529870.4 181328.4
 [64,] 529877.0 181330.0
 [65,] 529882.0 181333.0
 [66,] 529883.0 181334.0
 [67,] 529891.0 181345.0
 [68,] 529891.2 181345.6
 [69,] 529892.0 181348.0
 [70,] 529889.0 181372.0
 [71,] 529887.0 181386.0
 [72,] 529896.0 181388.0
 [73,] 529895.5 181389.7
 [74,] 529894.4 181393.6
 [75,] 529903.4 181396.0
 [76,] 529904.0 181396.2
 [77,] 529908.6 181397.5
 [78,] 529908.6 181397.5
 [79,] 529922.0 181401.1
 [80,] 529923.3 181401.5
 [81,] 529931.8 181403.9
 [82,] 529932.8 181404.1
 [83,] 529940.7 181406.3
 [84,] 529959.8 181411.6
 [85,] 529974.0 181415.5
 [86,] 529984.9 181418.5
 [87,] 529991.6 181420.3
 [88,] 529994.1 181421.0
 [89,] 530016.7 181427.2
 [90,] 530016.9 181427.3
 [91,] 530022.7 181428.8
 [92,] 530030.1 181430.9
 [93,] 530031.8 181431.4
 [94,] 530033.3 181431.8
 [95,] 530041.4 181434.0
 [96,] 530046.4 181435.3
 [97,] 530061.7 181439.5
 [98,] 530049.3 181460.3
 [99,] 530049.2 181460.4
[100,] 530049.1 181460.6
[101,] 530045.8 181466.2
[102,] 530044.1 181469.4
[103,] 530043.6 181470.4
[104,] 530042.6 181472.4
[105,] 530036.6 181483.7
[106,] 530035.3 181486.2
[107,] 530035.2 181486.4
[108,] 530034.7 181487.3
[109,] 530028.3 181499.4
[110,] 530027.7 181500.5
[111,] 530021.5 181512.3
[112,] 530021.1 181513.2
[113,] 530014.6 181525.6
[114,] 530011.3 181531.8
[115,] 530009.5 181535.2
[116,] 530010.3 181535.7
[117,] 530013.0 181537.2
[118,] 530019.8 181540.9
[119,] 530021.4 181541.6
[120,] 530026.6 181543.7
[121,] 530034.8 181547.0
[122,] 530035.7 181547.4
[123,] 530041.9 181549.9
[124,] 530044.7 181551.0
[125,] 530052.3 181554.1
[126,] 530052.6 181553.2
[127,] 530056.4 181543.9
[128,] 530065.7 181538.0
[129,] 530066.7 181537.3
[130,] 530069.3 181535.7
[131,] 530069.4 181535.0
[132,] 530070.1 181531.6
[133,] 530070.6 181530.8
[134,] 530074.5 181524.5
[135,] 530076.2 181521.8
[136,] 530075.8 181515.8
[137,] 530075.3 181508.0
[138,] 530075.1 181505.0
[139,] 530068.0 181501.0
[140,] 530063.0 181498.7
[141,] 530063.1 181498.3
[142,] 530065.4 181493.3
[143,] 530067.1 181489.3
[144,] 530067.0 181487.9
[145,] 530066.8 181486.3
[146,] 530067.6 181486.6
[147,] 530082.8 181492.1
[148,] 530084.1 181490.1
[149,] 530086.4 181486.3
[150,] 530089.1 181482.1
[151,] 530096.0 181471.0
[152,] 530096.2 181470.7
[153,] 530099.1 181465.6
[154,] 530105.8 181453.8
[155,] 530108.0 181450.0
[156,] 530109.5 181450.3
[157,] 530118.1 181452.1
[158,] 530127.7 181454.1
[159,] 530130.6 181454.7
[160,] 530132.0 181455.0
[161,] 530132.7 181455.2
[162,] 530136.0 181456.0
[163,] 530136.7 181454.8
[164,] 530137.4 181453.8
[165,] 530138.4 181452.1
[166,] 530138.7 181451.7
[167,] 530146.7 181439.1
[168,] 530160.0 181418.0
[169,] 530160.3 181417.6
[170,] 530163.0 181414.4
[171,] 530165.0 181412.0
[172,] 530166.0 181410.0
[173,] 530167.4 181410.0
[174,] 530171.3 181413.6
[175,] 530173.2 181413.3
[176,] 530174.0 181413.2
[177,] 530207.0 181434.0



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 530039.1 181373.1

Slot "ID":
[1] "2"

Slot "area":
[1] 47972.09


[[4]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 524404.7 185053.0

Slot "area":
[1] 9762.198

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
          [,1]     [,2]
 [1,] 524355.4 185053.6
 [2,] 524346.8 185064.2
 [3,] 524345.7 185065.5
 [4,] 524345.7 185065.5
 [5,] 524326.0 185087.7
 [6,] 524326.0 185087.8
 [7,] 524342.8 185107.2
 [8,] 524355.4 185108.2
 [9,] 524370.5 185109.4
[10,] 524388.5 185110.8
[11,] 524393.2 185111.2
[12,] 524396.5 185107.5
[13,] 524403.4 185097.4
[14,] 524407.2 185089.3
[15,] 524409.2 185083.7
[16,] 524410.3 185077.7
[17,] 524411.0 185077.2
[18,] 524413.6 185075.3
[19,] 524414.3 185074.6
[20,] 524419.9 185069.5
[21,] 524425.3 185063.0
[22,] 524427.1 185060.2
[23,] 524430.6 185054.8
[24,] 524473.7 185086.8
[25,] 524474.2 185087.2
[26,] 524480.0 185079.4
[27,] 524480.4 185078.9
[28,] 524489.4 185066.8
[29,] 524488.4 185066.0
[30,] 524487.8 185066.9
[31,] 524478.0 185061.0
[32,] 524449.4 185040.8
[33,] 524450.7 185040.1
[34,] 524451.2 185039.9
[35,] 524452.2 185038.6
[36,] 524461.9 185026.6
[37,] 524465.6 185020.5
[38,] 524468.8 185010.6
[39,] 524411.0 184986.3
[40,] 524410.0 184985.9
[41,] 524409.9 184985.9
[42,] 524407.8 184988.4
[43,] 524399.0 184999.1
[44,] 524399.0 184999.2
[45,] 524398.3 185000.0
[46,] 524394.2 185007.4
[47,] 524392.1 185009.9
[48,] 524388.7 185013.7
[49,] 524388.1 185014.4
[50,] 524376.2 185027.9
[51,] 524373.7 185031.0
[52,] 524370.5 185034.9
[53,] 524357.8 185050.6
[54,] 524357.8 185050.7
[55,] 524355.4 185053.6



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 524404.7 185053.0

Slot "ID":
[1] "3"

Slot "area":
[1] 9762.198


[[5]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 528694.5 184499.2

Slot "area":
[1] 13799.61

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
           [,1]     [,2]
  [1,] 528718.5 184565.0
  [2,] 528721.1 184565.0
  [3,] 528723.9 184564.9
  [4,] 528724.0 184564.9
  [5,] 528732.1 184564.7
  [6,] 528732.5 184564.7
  [7,] 528738.5 184564.5
  [8,] 528739.4 184564.5
  [9,] 528745.0 184564.4
 [10,] 528745.3 184564.3
 [11,] 528751.2 184564.2
 [12,] 528751.5 184564.2
 [13,] 528758.0 184564.0
 [14,] 528759.0 184564.0
 [15,] 528769.8 184563.7
 [16,] 528770.5 184563.7
 [17,] 528784.5 184563.3
 [18,] 528783.2 184562.2
 [19,] 528780.2 184559.6
 [20,] 528755.0 184537.8
 [21,] 528753.5 184536.9
 [22,] 528747.6 184533.4
 [23,] 528746.5 184533.1
 [24,] 528740.5 184531.5
 [25,] 528739.5 184531.2
 [26,] 528722.3 184532.4
 [27,] 528721.7 184531.8
 [28,] 528709.8 184518.6
 [29,] 528710.1 184518.2
 [30,] 528711.0 184517.1
 [31,] 528711.1 184516.5
 [32,] 528712.3 184504.6
 [33,] 528713.2 184494.7
 [34,] 528713.2 184494.6
 [35,] 528712.3 184491.9
 [36,] 528711.3 184490.6
 [37,] 528707.7 184485.6
 [38,] 528707.1 184484.9
 [39,] 528705.5 184483.5
 [40,] 528703.7 184481.4
 [41,] 528703.5 184481.1
 [42,] 528703.3 184480.9
 [43,] 528701.7 184480.1
 [44,] 528701.5 184480.0
 [45,] 528701.4 184479.6
 [46,] 528701.4 184479.5
 [47,] 528700.8 184477.2
 [48,] 528700.7 184476.7
 [49,] 528700.7 184476.7
 [50,] 528697.7 184470.8
 [51,] 528697.7 184469.0
 [52,] 528697.7 184462.3
 [53,] 528701.9 184440.4
 [54,] 528703.9 184430.3
 [55,] 528704.4 184430.0
 [56,] 528708.2 184437.7
 [57,] 528718.8 184459.2
 [58,] 528720.6 184462.7
 [59,] 528721.8 184465.2
 [60,] 528726.6 184474.9
 [61,] 528727.1 184475.9
 [62,] 528728.1 184478.0
 [63,] 528732.3 184486.5
 [64,] 528739.0 184500.0
 [65,] 528739.2 184500.5
 [66,] 528739.5 184501.4
 [67,] 528739.5 184501.0
 [68,] 528739.6 184500.5
 [69,] 528740.0 184496.6
 [70,] 528742.6 184495.0
 [71,] 528742.8 184494.9
 [72,] 528761.0 184477.4
 [73,] 528753.9 184450.1
 [74,] 528753.7 184450.0
 [75,] 528737.0 184440.9
 [76,] 528729.3 184428.2
 [77,] 528724.3 184420.0
 [78,] 528727.8 184404.6
 [79,] 528694.0 184405.0
 [80,] 528680.0 184411.0
 [81,] 528666.0 184418.0
 [82,] 528666.0 184418.2
 [83,] 528664.7 184422.6
 [84,] 528664.4 184423.8
 [85,] 528662.1 184431.6
 [86,] 528662.1 184431.8
 [87,] 528659.1 184444.4
 [88,] 528658.0 184449.2
 [89,] 528657.9 184449.9
 [90,] 528653.7 184468.0
 [91,] 528653.6 184468.2
 [92,] 528653.2 184470.0
 [93,] 528653.2 184470.2
 [94,] 528653.1 184470.5
 [95,] 528652.3 184474.1
 [96,] 528652.2 184474.4
 [97,] 528650.3 184482.8
 [98,] 528650.2 184483.0
 [99,] 528649.3 184486.9
[100,] 528649.1 184487.8
[101,] 528648.5 184490.3
[102,] 528648.4 184490.7
[103,] 528647.3 184495.7
[104,] 528647.1 184496.5
[105,] 528645.0 184505.5
[106,] 528644.8 184506.5
[107,] 528644.6 184507.3
[108,] 528644.5 184507.5
[109,] 528643.9 184510.4
[110,] 528643.5 184512.0
[111,] 528642.1 184518.3
[112,] 528641.8 184519.5
[113,] 528641.5 184520.5
[114,] 528641.4 184521.2
[115,] 528641.3 184521.3
[116,] 528641.0 184523.0
[117,] 528640.5 184524.9
[118,] 528639.2 184530.4
[119,] 528639.0 184531.6
[120,] 528637.7 184537.0
[121,] 528637.6 184537.5
[122,] 528637.0 184540.2
[123,] 528636.8 184540.9
[124,] 528635.5 184546.7
[125,] 528635.4 184546.8
[126,] 528634.2 184552.2
[127,] 528632.4 184561.1
[128,] 528628.9 184578.9
[129,] 528628.9 184578.9
[130,] 528628.7 184580.2
[131,] 528628.4 184581.4
[132,] 528654.1 184574.7
[133,] 528654.9 184574.5
[134,] 528659.3 184573.3
[135,] 528661.6 184572.7
[136,] 528661.7 184572.7
[137,] 528669.4 184570.7
[138,] 528675.7 184569.5
[139,] 528676.0 184569.5
[140,] 528680.2 184568.7
[141,] 528680.5 184568.6
[142,] 528681.0 184568.5
[143,] 528682.3 184568.3
[144,] 528685.5 184567.7
[145,] 528690.4 184566.8
[146,] 528692.6 184566.4
[147,] 528695.2 184565.9
[148,] 528696.8 184565.6
[149,] 528697.8 184565.6
[150,] 528706.8 184565.4
[151,] 528707.1 184565.4
[152,] 528718.5 184565.0



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 528694.5 184499.2

Slot "ID":
[1] "4"

Slot "area":
[1] 13799.61


[[6]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 529326.7 181750.0

Slot "area":
[1] 16969.09

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
           [,1]     [,2]
  [1,] 529332.4 181816.6
  [2,] 529336.9 181814.5
  [3,] 529341.9 181812.1
  [4,] 529343.2 181811.5
  [5,] 529347.8 181805.8
  [6,] 529347.9 181805.6
  [7,] 529348.3 181802.1
  [8,] 529348.8 181797.8
  [9,] 529348.8 181797.8
 [10,] 529347.8 181795.9
 [11,] 529343.8 181788.5
 [12,] 529342.1 181785.2
 [13,] 529348.0 181776.0
 [14,] 529350.7 181770.0
 [15,] 529352.6 181770.2
 [16,] 529352.7 181770.3
 [17,] 529361.4 181772.7
 [18,] 529366.8 181775.0
 [19,] 529371.0 181768.5
 [20,] 529373.2 181765.2
 [21,] 529373.6 181764.4
 [22,] 529369.0 181761.3
 [23,] 529376.3 181750.3
 [24,] 529378.4 181747.1
 [25,] 529380.0 181744.6
 [26,] 529380.2 181740.8
 [27,] 529381.0 181740.1
 [28,] 529382.5 181738.0
 [29,] 529388.7 181740.0
 [30,] 529413.0 181748.0
 [31,] 529416.1 181743.1
 [32,] 529420.1 181736.8
 [33,] 529421.1 181735.3
 [34,] 529421.5 181734.7
 [35,] 529423.1 181732.1
 [36,] 529423.2 181732.0
 [37,] 529430.4 181720.9
 [38,] 529430.0 181720.6
 [39,] 529429.4 181720.1
 [40,] 529412.1 181706.3
 [41,] 529412.0 181706.2
 [42,] 529411.8 181704.9
 [43,] 529413.3 181701.2
 [44,] 529419.6 181685.6
 [45,] 529414.9 181680.0
 [46,] 529415.4 181679.6
 [47,] 529415.5 181679.5
 [48,] 529412.8 181677.7
 [49,] 529411.5 181676.9
 [50,] 529410.0 181676.0
 [51,] 529400.9 181689.6
 [52,] 529398.0 181694.0
 [53,] 529397.0 181695.0
 [54,] 529396.0 181695.5
 [55,] 529395.0 181696.0
 [56,] 529393.4 181696.0
 [57,] 529392.4 181696.0
 [58,] 529391.2 181696.8
 [59,] 529390.5 181697.0
 [60,] 529386.2 181695.7
 [61,] 529383.8 181694.9
 [62,] 529383.7 181694.2
 [63,] 529383.4 181692.4
 [64,] 529382.8 181688.6
 [65,] 529382.1 181687.8
 [66,] 529372.9 181677.4
 [67,] 529376.1 181669.4
 [68,] 529387.0 181660.6
 [69,] 529387.0 181660.6
 [70,] 529385.5 181659.6
 [71,] 529384.2 181658.8
 [72,] 529383.4 181658.3
 [73,] 529380.9 181656.7
 [74,] 529379.5 181655.9
 [75,] 529368.7 181649.1
 [76,] 529366.9 181648.0
 [77,] 529359.3 181643.3
 [78,] 529358.5 181642.7
 [79,] 529357.9 181642.4
 [80,] 529355.4 181640.8
 [81,] 529355.1 181641.2
 [82,] 529342.4 181659.1
 [83,] 529342.4 181659.2
 [84,] 529336.8 181667.1
 [85,] 529336.7 181667.1
 [86,] 529329.9 181676.8
 [87,] 529329.9 181676.8
 [88,] 529328.5 181678.8
 [89,] 529325.0 181683.7
 [90,] 529325.0 181683.7
 [91,] 529323.0 181686.5
 [92,] 529317.2 181694.7
 [93,] 529315.2 181697.5
 [94,] 529315.0 181697.8
 [95,] 529310.1 181704.7
 [96,] 529293.3 181728.5
 [97,] 529284.2 181741.3
 [98,] 529283.3 181742.5
 [99,] 529281.2 181747.0
[100,] 529279.6 181750.3
[101,] 529278.5 181752.7
[102,] 529278.1 181753.6
[103,] 529273.4 181763.4
[104,] 529271.7 181765.9
[105,] 529270.8 181767.4
[106,] 529267.2 181771.8
[107,] 529266.3 181772.7
[108,] 529261.4 181777.8
[109,] 529261.0 181778.1
[110,] 529260.7 181778.5
[111,] 529254.1 181786.2
[112,] 529246.6 181795.0
[113,] 529238.9 181803.9
[114,] 529235.2 181808.1
[115,] 529232.9 181810.8
[116,] 529230.4 181814.1
[117,] 529230.2 181814.3
[118,] 529225.1 181820.9
[119,] 529223.4 181823.2
[120,] 529222.2 181824.7
[121,] 529219.2 181828.5
[122,] 529217.1 181831.2
[123,] 529217.0 181831.4
[124,] 529211.6 181838.3
[125,] 529211.4 181838.5
[126,] 529205.1 181846.7
[127,] 529205.2 181846.7
[128,] 529208.4 181847.3
[129,] 529213.8 181848.3
[130,] 529229.4 181851.2
[131,] 529306.3 181812.7
[132,] 529307.0 181812.3
[133,] 529310.7 181814.7
[134,] 529332.4 181816.6



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 529326.7 181750.0

Slot "ID":
[1] "5"

Slot "area":
[1] 16969.09



Slot "plotOrder":
[1] 3 1 2 6 5 4

Slot "bbox":
       min      max
x 524326.0 530660.2
y 181181.1 185111.2

Slot "proj4string":
CRS arguments:
 +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000
+y_0=-100000 +datum=OSGB36 +units=m +no_defs +ellps=airy
+towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894 

Oooo… it is one of those SPdataframe thingos with 5 variables now (try looking at OA.Census and Output.Areas in your Environment tab on the right to work out what is different between the two sp objects - what has happened?)

Basically… we have added some data to our map! 5 new variables are now in there about the number of White_Brittish citizens there are in an area, the Low_Occupancy info, how many Unemployed, and their Qualification. Go and look at the site we got the data from to find out more about this dataset (Practical 1 has information about where the data comes from: https://data.cdrc.ac.uk/dataset/aa5491c9-cbac-4026-97c9-f9168462f4ac/resource/09a1093a-74b9-487b-a939-d928f27be612/download/practical1.html).

Now. Many different coordinate systems are possible. If you are having trouble using GIS data this could well be what is going wrong. Here, we are going to set the coordinate system to the British National Grid (which is the format the data actually came in - we are just making sure, and it is an important thing to learn about):

proj4string(OA.Census) <- CRS("+init=EPSG:27700")
A new CRS was assigned to an object with an existing CRS:
+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +datum=OSGB36 +units=m +no_defs +ellps=airy +towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894
without reprojecting.
For reprojection, use function spTransform

Cool. A really good place to go if you want to learn more about mapping (as well as some of the R S4 classes like SpatialPolygonsDataFrame and how they work!) is this data camp course: https://campus.datacamp.com/courses/working-with-geospatial-data-in-r. Chapters 2 onwards are very nice, and provide a good introduction to the sp, raster and rgdal packages, setting coordinate systems etc. I strongly recommend working through this course if you want to find out more about what we are doing here (we are skimming through!)

Now… we could make our map look nicer. Let’s use the tmap package, which works quite a bit like ggplot (i.e. it layers the graphics up, so is quite powerful).

library(tmap)

Have a look at ?tm_shape and ?tm_fill and you will start working out how it can be used. For a list of all possible functions try ?tmap. That Data Camp course I mentioned above (https://campus.datacamp.com/courses/working-with-geospatial-data-in-r) is the place to go if you want to find out more about how tmap works. We don’t have time to cover it here.

Let’s try using it! What is the spread of Qualifications acorss Camden?

tm_shape(OA.Census) + tm_fill("Qualification") 

Nice - you can find out a lot more about mapping options by working through the rest of Practical 5 on https://data.cdrc.ac.uk/tutorial/an-introduction-to-spatial-data-analysis-and-visualisation-in-r (we are going to move onto more statistical things!)

More information

We are not going to cover mapping in any more detail - you could easily complete a whole course just in this! For more information you could start with the following two resources (which I have already referred to above!)

Point Pattern Analysis

So… we have a map. Let’s put some more data onto it. The same site makes some point data about house prices available via this link: https://data.cdrc.ac.uk/dataset/aa5491c9-cbac-4026-97c9-f9168462f4ac/resource/24c4f527-43c8-4c09-8558-ad6a48e17de5/download/camdenhousesales15.csv

Let’s look at it (make sure you ahve downloaded the data from the site! You will need to log in to access it which is why we are not bothering to read it directly):

houses <- read.csv("CamdenHouseSales15.csv")
houses

Right-o. We have seen things like this before. Let’s quickly plot out what looks like the lattitude/longitude data:

plot(houses$oseast1m, houses$osnrth1m)

Yep - it also looks like Cambden! We can probably just map the two datasets together. If we turn this object (which is just a dataframe) into a SpatialPointsDataFrame (like OA.Census) then we will be able to layer them on one another! We need to be a bit careful about that coordinate frame thing again though (i.e. we need to set it again).

So. We need to set what the data is to be included (houses), what columns contain the x and y coordinates (houses[,3:4]), and what projection system we are using (CRS("+init=EPSG:27700")).

House.Points <-SpatialPointsDataFrame(houses[,8:9], houses, proj4string = CRS("+init=EPSG:27700"))

Let’s print it just to be sure:

House.Points
class       : SpatialPointsDataFrame 
features    : 2547 
extent      : 524048, 531511, 181067, 187470  (xmin, xmax, ymin, ymax)
coord. ref. : +init=EPSG:27700 +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +datum=OSGB36 +units=m +no_defs +ellps=airy +towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894 
variables   : 9
names       :    UID,    Price,            Date,     Street,  District,         Region, Postcode, oseast1m, osnrth1m 
min values  : 284509,      400, 01/02/2015 0:00, ABBEY ROAD,    CAMDEN, GREATER LONDON,  EC1M3HA,   524048,   181067 
max values  : 927842, 22500000, 12/31/2015 0:00,   YORK WAY, ISLINGTON, GREATER LONDON,  WC2H9RG,   531511,   187470 
# creates a coloured dot map
tm_shape(OA.Census) + tm_borders(alpha=.4) +
tm_shape(House.Points) + tm_dots(col = "Price", palette = "Reds", style = "quantile") 

Alright! That’s kind of nice! Again. You can keep going, and adding to this map if you check out Practical 6 of https://data.cdrc.ac.uk/tutorial/an-introduction-to-spatial-data-analysis-and-visualisation-in-r, we are going to move onto Kernel smoothing!

Kernel smoothing

A point pattern is really just a collection of geographical points, that are assumed to be generated by a random process. Let’s imagine the series of points in an \((x,y)\) coordinate system, then we can imagine the vector of \(n\) observations: \({\bf{x}_i}=\{(x_1, y_1), (x_2,y_2)\dots, (x_n,y_n)\}\) for some variable of interest.

One way to analyse these type of point distributions is to perform kernel smoothing, where you replace each point \(x_i\) with a kernel, which is just a simple localised function \(f({\bf x_i})\) centred on each of our points. We can then and add up all these kernels to get a smooth intensity function, which describes how the distribution of points behaves over space. You could really just think of this as a “bump averaging process”.

To visualise this process, imagine that you have some blotter paper, and you are putting a dot of ink at each point over your paper. The ink will spread out, with a darker spot in the centre. If you do this for a lot of different dots, then they will start to overlap, getting darker. That is your intensity function!

You need to decide things like what type of kernel function to use, what shape it has etc. but the density function in spatstat has some pretty good ones for you to use if you need something different. (This data camp course gives a good introduction: https://campus.datacamp.com/courses/spatial-statistics-in-r/). Here, we are going to use a more modern package that couples very nicely with our tmap object.

The kernelUD function runs a straightforward estimation of our house price data:

library(adehabitatHR)
Loading required package: deldir
deldir 0.1-14
Loading required package: ade4
Loading required package: adehabitatMA
Loading required package: adehabitatLT
Loading required package: CircStats
Loading required package: MASS
Loading required package: boot
# runs the kernel density estimation,look up the function parameters for more options
kde.output <- kernelUD(House.Points, h="href", grid = 1000)
xy should contain only one column (the id of the animals)
id ignored
plot(kde.output)

Interesting. Can we put it on our map? First we have to convert it to a raster object, and set its coordinate system, so that we can then map it onto our previous map:

library(raster)

Attaching package: ‘raster’

The following objects are masked from ‘package:MASS’:

    area, select

The following object is masked from ‘package:adehabitatMA’:

    buffer
#convert our kernel density map to a raster object
kde <- raster(kde.output)
# set the coordinate projection of our object to British National Grid (the one we have been using all along)
projection(kde) <- CRS("+init=EPSG:27700")
#map it!
tm_shape(kde) + tm_raster("ud")

We can zoom in to match it to our previous map (if you have forgotten what that was then go back up and remind yourself of what the Output.Areas map was!)

masked_kde <- mask(kde, Output.Areas)
plot(masked_kde) # a quick sanity check!

(There is normally a good bet that the plot function will exist for things of these type, so it is worth a try if you don’t know what to do with something… that is pretty much what we did here ;)

Nice! Looks like things are working… Let’s neaten it up a bit with some of the functionality built for tmap!

library(tmaptools) # provides a set of tools for processing spatial data
# creates a bounding box based on the extents of the Output.Areas polygon (to make our map smaller)
bounding_box <- bb(Output.Areas)
# maps the raster within the bounding box
tm_shape(masked_kde, bbox = bounding_box) + tm_raster("ud")

But if we want to get something nicer still we can keep on fiddling… I will leave it for you to look up all the calls in the help!

tm_shape(masked_kde, bbox = bounding_box) + tm_raster("ud", style = "quantile", n = 100, legend.show = FALSE, palette = "YlGnBu") +
tm_shape(Output.Areas) + tm_borders(alpha=.3, col = "white") +
tm_layout(frame = FALSE)

Nice! That tells us a lot about how house prices are changing as we move around in Camden. (Any groups think that kind of thing might be useful? ;)

More information

Spatial Attribute Analysis

Quite often we get data in regions (e.g. LGA, SA4 etc.) instead of as a point function. This is so common that there are a whole range of techniques for dealing with it.

Spatial Autocorrelaton

Spatial autocorrelation is an extension of temporal autocorrelation (which is covered in the workbook on Time Series). It is a bit more complex though, as spatial objects have (at least) two dimensions and, like we have seen above, the regions can have complex shapes. This means that it may not be obvious how to determine what is “near”, and there are lots of different measures of this (we are just going to consider one, but you will find lots of resources about other methods as you work through this section).

A spatial autocorrelation measures how distance influences a particular variable. Basically, we expect things that are close together to be similar. So for example, a contagious disease is more likely to spread to people who live close to each other, or people tend to cluster together in suburbs with people like them. Can we think of a variable that might do this in our dataset? What about qualifications? You might expect that suburbs with a lot of people with degrees will tend to cluster together perhaps…

Let’s go back to our map, and adjust it a bit to see if this might be occurring in Camden.

tm_shape(OA.Census) + tm_fill("Qualification", palette = "Reds", style = "quantile", title = "% with a Qualification") + tm_borders(alpha=.4)  

Looks like this might be happening actually. How could we test whether this is statistically significant though? We will use the spdep package to look at spatial autocorrelation.

library(spdep)
Loading required package: Matrix

Attaching package: ‘spdep’

The following object is masked from ‘package:ade4’:

    mstree

First, we have to find out which polygons in our map are neighbours with one another. We are going to use one particular method here:

neighbours <- poly2nb(OA.Census, queen = FALSE)
neighbours
Neighbour list object:
Number of regions: 749 
Number of nonzero links: 4176 
Percentage nonzero weights: 0.7443837 
Average number of links: 5.575434 

By setting queen = FALSE we have set up our map to use a definition of neighbours where more than one shared point is required for two regions to be defined as neighbouring one another. (Look up more options in ?poly2nb and you can find out a lot more details about this in these slides: http://www.bias-project.org.uk/ASDARcourse/unit6_slides.pdf).

We can plot this list of neighbours on our map

plot(OA.Census, border = 'lightgrey')
plot(neighbours, coordinates(OA.Census), add=TRUE, col='red')

Ok. Now we can run an autoregression. First we have to convert our neighbours object to the right kind of data object, one that has weights:

listw <- nb2listw(neighbours)
listw
Characteristics of weights list object:
Neighbour list object:
Number of regions: 749 
Number of nonzero links: 4176 
Percentage nonzero weights: 0.7443837 
Average number of links: 5.575434 

Weights style: W 
Weights constants summary:
    n     nn  S0       S1       S2
W 749 561001 749 285.3793 3113.982

Compare listw and neighbours. See that our new list has extra information about weights? We have specified what type of coding scheme we are going to use, that is, how neighbours with no links should be treated etc. See the preliminary details at ?nb2listw, but if you want to find out more about this process then you could check out slides 23-26 of this set: http://www.bias-project.org.uk/ASDARcourse/unit6_slides.pdf (Lots of other details in here too!)

Ok. We can now run a test for spatial autocorrelation! We are going to use Moran’s test, which creates a correlation score between -1 and 1. Have a look at ?moran to find out more about Moran’s I works, but basically it measures spatial autocorrelation based on both feature locations and feature values simultaneously. (See the wikipedia page for a bit more info: https://en.wikipedia.org/wiki/Moran%27s_I) Enough already - lets do the test! Are the regions autocorrelated?

moran.test(OA.Census$Qualification, listw)

    Moran I test under randomisation

data:  OA.Census$Qualification  
weights: listw  

Moran I statistic standard deviate = 24.292, p-value <
2.2e-16
alternative hypothesis: greater
sample estimates:
Moran I statistic       Expectation          Variance 
     0.5448699398     -0.0013368984      0.0005055733 

Ok. Our p-value is significant and our I statistic is positive (i.e correlated). So the regions seem to be somewhat correlated, as we expected to see from the red image above where we saw that regions with more qualifications tended to cluster together. This page has more details about interpreting Moran’s I, athough it is for a different package from R: http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/How_Spatial_Autocorrelation_Global_Moran_s_I_works/005p0000000t000000/

This is what is known as a global autocorrelation test. We are looking over the whole map to measure spatial correlation.

We can also do a local test for autocorrelation. Let’s start by looking at how the Qualifications are changing against spatially lagged values. If you want to find out more about how this works, then this page is a great place to start: http://rspatial.org/analysis/rst/3-spauto.html

moran <- moran.plot(OA.Census$Qualification, listw = nb2listw(neighbours, style = "W"))

Hmmm… seems like there might be some sort of a positive relationship? There are quite a few outliers, perhaps we can learn a bit more. The localmoran function is what we need (check the help file)

local <- localmoran(x = OA.Census$Qualification, listw = nb2listw(neighbours, style = "W"))
head(local)
           Ii         E.Ii    Var.Ii        Z.Ii  Pr(z > 0)
0  0.04369897 -0.001336898 0.2486902  0.09030862 0.46402099
1  0.05684782 -0.001336898 0.2486902  0.11667547 0.45355861
2 -0.13604966 -0.001336898 0.1415364 -0.35807555 0.63985661
3  0.49387693 -0.001336898 0.3320321  0.85941460 0.19505591
4  0.64934401 -0.001336898 0.1415364  1.72955349 0.04185504
5 -0.28284849 -0.001336898 0.4987159 -0.39862974 0.65491698

Right… so this is producing a whole set of values for each region! We could add this to our shapefile and then we would be able to map it…

# binds results to our polygon shapefile
moran.map <- cbind(OA.Census, local)
# maps the results
tm_shape(moran.map) + tm_fill(col = "Ii", style = "quantile", title = "local moran statistic") 

So this shows us the variations in autocorrelation across space. But are they significant? We could try mapping the p-values the same way. First we need to work out what they are called:

names(moran.map@data)
 [1] "OA11CD"        "White_British" "Low_Occupancy" "Unemployed"   
 [5] "Qualification" "Ii"            "E.Ii"          "Var.Ii"       
 [9] "Z.Ii"          "Pr.z...0."    
# maps the p-values
tm_shape(moran.map) + tm_fill(col = "Pr.z...0.", style = "fixed", breaks=c(0.001,0.01,0.05,0.1,0.2,1), title = "p-values") 

Interesting… Can you interpret this? Is it what you expected? (Make sure you look at both the local moran statistics and the p-values in interpreting your results.)

In practice you should really be comparing this to a randomly generated Markov Chain approach. The Data Camp course on https://campus.datacamp.com/courses/spatial-statistics-in-r/ goes into this in a lot of detail.

More information

Geographically Weighted Regression

Ok… final step! Can we work out how to use areas in a regression model? Yes we can! Geographically Weighted Regression (GWR) can be used to identify how regression coefficients may vary across the study area. (So it relaxes assumptions about stationarity for spatial data.)

Standard linear regression over a geographical dataset

First, let’s try running just a normal regression model, that tries to explain Qualifications in terms of the other variables in the census dataset:

lm.model <- lm(OA.Census$Qualification ~ OA.Census$Unemployed+OA.Census$White_British)
summary(lm.model)

Call:
lm(formula = OA.Census$Qualification ~ OA.Census$Unemployed + 
    OA.Census$White_British)

Residuals:
    Min      1Q  Median      3Q     Max 
-50.311  -8.014   1.006   8.958  38.046 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)             47.86697    2.33574   20.49   <2e-16 ***
OA.Census$Unemployed    -3.29459    0.19027  -17.32   <2e-16 ***
OA.Census$White_British  0.41092    0.04032   10.19   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 12.69 on 746 degrees of freedom
Multiple R-squared:  0.4645,    Adjusted R-squared:  0.463 
F-statistic: 323.5 on 2 and 746 DF,  p-value: < 2.2e-16

Its not a bad model. Explains 46.5% of the variance, good p-values… what do the residuals look like?

plot(lm.model)

Not brillant, but kind of ok. Is there a spatial distribution to them though? (There should be - we just found it using the spatial autocorrelation stuff!)

resids<-residuals(lm.model)
map.resids <- cbind(OA.Census, resids) 
# we need to rename the column header from the resids file - in this case its the 6th column of map.resids
names(map.resids)[6] <- "resids"
# maps the residuals using the quickmap function from tmap
qtm(map.resids, fill = "resids")

tm_shape(map.resids) + tm_fill("resids") 

Seems like there might be a bit of a spatial dependence there.

GWR

Ok. Can we take account of spatial variables along with our regression model? First we need to work out how to model the kernel. We will use

library("spgwr")
NOTE: This package does not constitute approval of GWR
as a method of spatial analysis; see example(gwr)
#calculate kernel bandwidth
GWRbandwidth <- gwr.sel(OA.Census$Qualification ~ OA.Census$Unemployed+OA.Census$White_British, data=OA.Census,adapt=T)
Adaptive q: 0.381966 CV score: 101420.8 
Adaptive q: 0.618034 CV score: 109723.2 
Adaptive q: 0.236068 CV score: 96876.06 
Adaptive q: 0.145898 CV score: 94192.41 
Adaptive q: 0.09016994 CV score: 91099.75 
Adaptive q: 0.05572809 CV score: 88242.89 
Adaptive q: 0.03444185 CV score: 85633.41 
Adaptive q: 0.02128624 CV score: 83790.04 
Adaptive q: 0.01315562 CV score: 83096.03 
Adaptive q: 0.008130619 CV score: 84177.45 
Adaptive q: 0.01535288 CV score: 83014.34 
Adaptive q: 0.01515437 CV score: 82957.49 
Adaptive q: 0.01436908 CV score: 82857.74 
Adaptive q: 0.01440977 CV score: 82852.4 
Adaptive q: 0.01457859 CV score: 82833.25 
Adaptive q: 0.01479852 CV score: 82855.45 
Adaptive q: 0.01461928 CV score: 82829.32 
Adaptive q: 0.01468774 CV score: 82823.82 
Adaptive q: 0.01473006 CV score: 82835.89 
Adaptive q: 0.01468774 CV score: 82823.82 

Ok. Now we can use this value of the bandwidth in our model (don’t forget to look up the relevant help pages to find out what we are doing here!)

#fit the gwr model (note it has the same formula as before)
gwr.model = gwr(OA.Census$Qualification ~ OA.Census$Unemployed+OA.Census$White_British, data = OA.Census, adapt=GWRbandwidth, hatmatrix=TRUE, se.fit=TRUE) 
#OK. What did it do?
gwr.model
Call:
gwr(formula = OA.Census$Qualification ~ OA.Census$Unemployed + 
    OA.Census$White_British, data = OA.Census, adapt = GWRbandwidth, 
    hatmatrix = TRUE, se.fit = TRUE)
Kernel function: gwr.Gauss 
Adaptive quantile: 0.01468774 (about 11 of 749 data points)
Summary of GWR coefficient estimates at data points:
                            Min.  1st Qu.   Median  3rd Qu.
X.Intercept.            11.08183 34.43427 45.76862 59.75372
OA.Census.Unemployed    -5.45291 -3.28308 -2.55398 -1.79413
OA.Census.White_British -0.28046  0.19955  0.37788  0.53216
                            Max.  Global
X.Intercept.            85.01866 47.8670
OA.Census.Unemployed     0.77019 -3.2946
OA.Census.White_British  0.94678  0.4109
Number of data points: 749 
Effective number of parameters (residual: 2traceS - traceS'S): 132.6449 
Effective degrees of freedom (residual: 2traceS - traceS'S): 616.3551 
Sigma (residual: 2traceS - traceS'S): 9.903539 
Effective number of parameters (model: traceS): 94.44661 
Effective degrees of freedom (model: traceS): 654.5534 
Sigma (model: traceS): 9.610221 
Sigma (ML): 8.983902 
AICc (GWR p. 61, eq 2.33; p. 96, eq. 4.21): 5633.438 
AIC (GWR p. 96, eq. 4.22): 5508.777 
Residual sum of squares: 60452.16 
Quasi-global R2: 0.7303206 

So… what happened? Let’s compare a few things. First - what are the components of the models?

names(lm.model)
 [1] "coefficients"  "residuals"     "effects"       "rank"         
 [5] "fitted.values" "assign"        "qr"            "df.residual"  
 [9] "xlevels"       "call"          "terms"         "model"        
names(gwr.model)
 [1] "SDF"       "lhat"      "lm"        "results"   "bandwidth"
 [6] "adapt"     "hatmatrix" "gweight"   "gTSS"      "this.call"
[11] "fp.given"  "timings"  

What if we look at the coefficients for the global model (i.e. the standard linear regression fit) again?

lm.model$coefficients
            (Intercept)    OA.Census$Unemployed 
             47.8669683              -3.2945908 
OA.Census$White_British 
              0.4109194 

How do these compare with the ranges of the intercept and the model coefficients in the summary for gwr.model? What has changed by us running a local regression? They are not completely different, but if we compare the Median values then we see that they have changed a little bit.

This is because in our GWR, we have sets of these intercept and coefficient values for each map region (along with a whole heap of information about the error of the fit at that point) . We can look at them easily if we force the part of the model with the fit.points etc. to a data.frame

results <-as.data.frame(gwr.model$SDF)
results

Ha. So the coefficients are changing for each council region, along with the intercepts, and some other bits and pieces.

Just as a by the way… we are using the @ here to refer to a slot in the S4 object that we know is a data.frame (because of the help pages). Here is another way to force out the same information that is probably a bit more familiar:

gwr.model$SDF@data

Exactly the same right? If you want to find out more about S4 functions then you should go and do Chapter 2 of this Data Camp course: https://campus.datacamp.com/courses/working-with-geospatial-data-in-r/ which goes into what sp objects are (objects of class S4), what this means, and how they behave in quite a bit of detail.

If we don’t force the sp object to a data.frame then we can call its native plot functions

spplot(gwr.model$SDF)

Fancy. We can see how they change. Its a bit slow though. And not really a good idea to compare them like this. However, if we want to then we can map out individual results data again…

gwr.map <- cbind(OA.Census, as.matrix(results))
tm_shape(gwr.map) + tm_fill("localR2")

If you want to see more about how to render the different bits in comparison graphs that use different scales (which is where the above plot call really falls down) then look up gridExtra. (See the end of Practical 10 of https://data.cdrc.ac.uk/tutorial/an-introduction-to-spatial-data-analysis-and-visualisation-in-r for a quick introduction to using this very handy package.)

More information

LS0tCnRpdGxlOiAiU3BhdGlhbCBBbmFseXNpcyIKYXV0aG9yOiAiS2lyc3R5IEtpdHRvIgpkYXRlOiAiTWF5IDI2IDIwMTgiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KClNwYXRpYWwgZGF0YSBicmluZ3MgYSB3aG9sZSBzZXQgb2YgbmV3IHByb2JsZW1zIHdpdGggaXQuIEEgcG9pbnQgb2YgcGFydGljdWxhciBkaXZlcmdlbmNlIGZyb20gb3VyIHJlZ3Jlc3Npb24gbW9kZWxzLCBpcyBicm91Z2h0IG9uIGJ5IHRoZSBmYWN0IHRoYXQgc3BhdGlhbCBkYXRhIGlzIG9mdGVuIGF1dG9jb3JyZWxhdGVkIGluIHRoZSByYW5kb20gY29tcG9uZW50LiBUaGF0IG1lYW5zIHRoYXQgbmVhcmJ5IGVycm9ycyBhcmUgb2Z0ZW4gY29ycmVsYXRlZCwgYW5kIHZpb2xhdGVzIG9uZSBvZiBvdXIgY29yZSBhc3N1bXB0aW9ucyBvZiByZWdyZXNzaW9uIChhYm91dCB0aGUgZXJyb3IgdGVybXMgYmVpbmcgaW5kZXBlbmRlbnQgZnJvbSBvbmUgYW5vdGhlcikuIFdlIG5lZWQgdG8gYWRqdXN0IG91ciBtb2RlbHMgdG8gYWNjb3VudCBmb3IgdGhpcyBwcm9ibGVtLiAKCldpdGggc3BhdGlhbCBkYXRhIHdlIGFyZSBvZnRlbiBpbnRlcmVzdGVkIGluIGFza2luZyBxdWVzdGlvbnMgYWJvdXQgdGhpbmdzIGxpa2U6CgoqIHdoZXRoZXIgb3VyIGRhdGFwb2ludHMgYXJlIHNwYXRpYWxseSBjbHVzdGVyZWQ/CiogaWYgdHdvIHR5cGVzIG9mIGV2ZW50IGhhdmUgdGhlIHNhbWUgdHlwZSBvZiBzcGF0aWFsIGRpc3RyaWJ1dGlvbj8gKGUuZy4gdHdvIGRpZmZlcmVudCB0eXBlcyBvZiBjcmltZSwgb3IgdHdvIGRpZmZlcmVudCBkaXNlYXNlcykKKiB3aGV0aGVyIGEgY29udGFnaW9uIGxpZXMgYmVoaW5kIGFuIG91dGJyZWFrIG9mIGEgZGlzZWFzZT8gKGkuZS4gaXMgYSBuZXcgY2FzZSBtb3JlIGxpa2VseSB0byBvY2N1ciBuZWFyIG9uZSBvZiB0aGUgZXhpc3RpbmcgcG9pbnRzIGluIGEgZGF0YXNldD8pCiogaXMgYW4gYXBwYXJlbnQgY2x1c3RlciBvZiBhY2NpZGVudHMganVzdCBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGVyZSBhcmUgbG90cyBvZiBwZW9wbGUgYXJlIGNyb3NzaW5nIHRoZSByb2FkIHRoZXJlPyAKClIgaGFzIGEgd2hvbGUgc3VpdGUgb2YgdG9vbHMgZm9yIGRlYWxpbmcgd2l0aCBzcGF0aWFsIGRhdGEuIEFuZCB0aGUgdmlzdWFsaXNhdGlvbiBjYXBhYmlsaXRpZXMgaW4gcGFydGljdWxhciBhcmUgdmVyeSBuaWNlbHkgc2V0IHVwLiBMZXQncyBzcGVuZCBhIGxpdHRsZSBiaXQgb2YgdGltZSBsb29raW5nIGF0IG1hcHBpbmcgYmVmb3JlIHdlIG1vdmUgb250byBnZW5lcmF0aW5nIHNvbWUgc3RhdGlzdGljYWwgbW9kZWxzIGZvciBvdXIgZGF0YS4gCgpJZiB5b3UgcmVhbGx5IHdhbnQgdG8gZmluZCBvdXQgYWJvdXQgaG93IHRvIGRlYWwgd2l0aCBzcGF0aWFsIGRhdGEgaW4gUiwgdGhlbiB0aGlzIGlzIGEgZ3JlYXQgc2l0ZSwgZnVsbCBvZiBzb21lIGxvdmVseSB0dXRvcmlhbHMgb24gZXZlcnl0aGluZyB5b3UgYXJlIGxpa2VseSB0byB3YW50IHRvIGtub3c6IGh0dHBzOi8vZGF0YS5jZHJjLmFjLnVrL3R1dG9yaWFsL2FuLWludHJvZHVjdGlvbi10by1zcGF0aWFsLWRhdGEtYW5hbHlzaXMtYW5kLXZpc3VhbGlzYXRpb24taW4tciAKCkkgZGVmaW5pdGVseSByZWNvbW1lbmQgdGhpcyBzaXRlISBZb3Ugd2lsbCBuZWVkIHRvIGNyZWF0ZSBhbiBhY2NvdW50IGFuZCBsb2cgaW4sIGJ1dCBpdCBpcyBkZWZpbml0ZWx5IHdvcnRoIHlvdXIgd2hpbGUuIEl0IGhhcyB2ZXJ5IG5pY2Ugd29ya2Jvb2tzIG9uIFBvaW50IG1hcHBpbmcsIGtlcm5lbCBzbW9vdGhpbmcsIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLi4uIGFsbW9zdCBldmVyeXRoaW5nIHlvdSBhcmUgbGlrZWx5IHRvIGtub3cuIEkgaGF2ZSB0YWtlbiBhIGxvdCBvZiB3aGF0IGZvbGxvd3MgZnJvbSB0aGF0IHNpdGUsIGJ1dCB0aGlzIHdvcmtib29rIHdpbGwgb25seSBiZSBzY3JhdGNoaW5nIHRoZSBzdXJmYWNlIG9mIHdoYXQgaXMgdGhlcmUhIChBbGJlaXQgaW4gb25lIHJlbGF0aXZlbHkgcXVpY2sgdG8gd29yayB0aHJvdWdoIHdvcmtib29rIGFzIG9wcG9zZWQgdG8gdGhlIDEyIFByYWN0aWNhbHMgdGhhdCB5b3Ugd2lsbCBmaW5kIGluIHRoYXQgc2l0ZSEpCgojI01hcHBpbmcKCldoZW4gd2UgYXJlIGRlYWxpbmcgd2l0aCBzcGF0aWFsIGRhdGEsIHdlIGNhbiBvZnRlbiBlbmQgdXAgd2l0aCBhIG51bWJlciBvZiBkaWZmZXJlbnQgdHlwZXMgb2YgZGF0YSBhbmQgdGhlc2UgY2FuIGJlIHN0b3JlZCBpbiBxdWl0ZSBjb21wbGV4IGRhdGF0eXBlcy4gRm9yIGV4YW1wbGUsIG1hcHMgb2Z0ZW4gaW5jbHVkZToKCiogcG9pbnQgZGF0YSAoZS5nLiBzcGVjaWZpYyBwbGFjZXMgd2hlcmUgc29tZSBldmVudCBvY2N1cnMpCiogbGluZSBkYXRhIChkYXRhIGFzc29jaWF0ZWQgd2l0aCBhIGxpbmUsIHdoaWNoIHdlIGdldCBieSBqb2luaW5nIHR3byBwb2ludHMgZS5nLiByaXZlcnMsIHJvYWRzKQoqIHBvbHlnb24gZGF0YSAoZGF0YSBhc3NvY2lhdGVkIHdpdGggYW4gYXJlYSwgZS5nLiBTQTIpCiogcmFzdGVyIGRhdGEgKGRhdGEgYXNzb2NpYXRlZCB3aXRoIGEgZ3JpZCwgZS5nLiBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlKQoKVGhlIGBzcGAgcGFja2FnZSBpcyBhIHN0YW5kYXJkIHdheSBvZiBkZWFsaW5nIHdpdGggc3BhdGlhbCBkYXRhIChzdG9yZWQgYXMgb2JqZWN0cyBvZiB0eXBlIFNwYXRpYWwgUG9seWdvbnMpLiBNYW55IHBhY2thZ2VzIGRlcGVuZCB1cG9uIGl0LCBzbyBpdCBpcyB3b3J0aCBsZWFybmluZyBhYm91dCBpZiB5b3UgYXJlIHBsYW5uaW5nIHRvIGRvIGFueXRoaW5nIHdpdGggc3BhdGlhbCBkYXRhLiAKCk9mdGVuIHdlIHdpbGwgZ2V0IGluZm9ybWF0aW9uIGFib3V0IHNwYXRpYWwgb2JqZWN0cyAoaS5lLiBtYXBzKSBmcm9tIHdoYXQgaXMgY2FsbGVkIGFuICpPR1IgZGF0YSBzb3VyY2UqLCB3aGljaCBpcyBzb21ldGhpbmcgdGhhdCBoYXMgYmVlbiBjb25zdHJ1Y3RlZCBhY2NvcmRpbmcgdG8gdGhlIEdlb3NwYXRpYWwgRGF0YSBBYnN0cmFjdGlvbiBMaWJyYXJ5IChHREFMKSwgd2hpY2ggaXMgcmVhbGx5IGp1c3QgYSBkYXRhIHN0YW5kYXJkIGZvciBnZW9zcGF0aWFsIGRhdGEgKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dEQUwpLiAKClIgaGFzIHNvbWUgcHJldHR5IGdvb2QgdG9vbHMgZm9yIGRlYWxpbmcgd2l0aCB0aGlzIHN0dWZmLiBJbiBwYXJ0aWN1bGFyLCB0aGUgYHJlYWRPR1IoKWAgZnVuY3Rpb24gaW4gdGhlIGByZ2RhbGAgcGFja2FnZSwgY2FuIGJlIHVzZWQgdG8gcmVhZCBpbiBPR1IgZGF0YS4gTGV0J3MgbG9hZCBpdDoKCmBgYHtyfQpsaWJyYXJ5KHNwKQpsaWJyYXJ5KHJnZGFsKQpgYGAKCldlIGNhbiB1c2UgYHJlYWRPR1JgIHRvIGxvYWQgdXAgdGhlIE9HUiBmaWxlcyB0aGF0IGhhdmUgYmVlbiBtYWRlIGF2YWlsYWJsZSBoZXJlOiBodHRwczovL2RhdGEuY2RyYy5hYy51ay9kYXRhc2V0L2FhNTQ5MWM5LWNiYWMtNDAyNi05N2M5LWY5MTY4NDYyZjRhYy9yZXNvdXJjZS9mOGVjYzJiYy01MzEzLTQ2OGQtOTY1My0xMWYwZmQ3NTJhN2QvZG93bmxvYWQvY2FtZGVub2ExMS56aXAgCgpNYWtlIHN1cmUgdGhhdCB5b3UgZG93bmxvYWQgdGhlbSBub3csIGFuZCBtb3ZlIHRoZW0gdG8gdGhlIGRpcmVjdG9yeSB3aGVyZSB5b3UgYXJlIHJ1bm5pbmcgeW91ciBjb2RlISAoaS5lLiB0aGUgcGF0aG5hbWUgbWlnaHQgbm90IHdvcmshKSBIYXZlIGEgbG9vayBhdCB0aGUgZmlsZXMgLSB0aGV5IHNob3VsZCBsb29rIGxpa2UgdGhpczoKCiogIENhbWRlbl9vYTExLmRiZgoqICBDYW1kZW5fb2ExMS5wcmoKKiAgQ2FtZGVuX29hMTEuc2hwCiogIENhbWRlbl9vYTExLnNoeAoKUiBrbm93cyBob3cgdG8gbG9hZCB0aGVtIGFsbCBpZiB5b3Ugc3BlY2lmeSB0aGUgcGF0aCBuYW1lICgiQ2FtYmRlbiIgZm9yIG1lIC0gSSBoYXZlIHRoZW0gaW4gYSBmb2xkZXIpIGFuZCB0aGUgbmFtZSBvZiB0aGUgZmlsZSAoaS5lLiB0aGUgYml0IG91dCB0aGUgZnJvbnQgd2l0aG91dCB0aGUgZmlsZW5hbWUgZXh0ZW5zaW9uLikKCmBgYHtyfQpPdXRwdXQuQXJlYXM8LSByZWFkT0dSKCJDYW1kZW4iLCJDYW1kZW5fb2ExMSIpCmBgYAoKUmVtZW1iZXIgdG8gcnVuIGA/cmVhZE9HUmAgdG8gZmluZCBvdXQgbW9yZSBhYm91dCB0aGlzIGZ1bmN0aW9uIChhbmQgdGhlIE9HUiBmb3JtYXQpLgoKWW91IGNvdWxkIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSB0aGlzIG1hcCB1c2luZyBgc3RyKE91dHB1dC5BcmVhcylgIGJ1dCBpdHMgUkVBTExZIGxvbmchIEkgZG8gcmVjb21tZW5kIHlvdSBleGFtaW5lIHRoZSBzdHJ1Y3R1cmUgb2YgdGhpcyBiZWFzdHkgYXQgbGVhc3Qgb25jZSB0byBnZXQgYSBmZWVsaW5nIGZvciB3aGF0IGlzIGdvaW5nIG9uIGluIGl0LiBBbHNvIC0gYmV3YXJlIC0gdGhlIGFjdHVhbCBkYXRhIG9iamVjdCBpdHNlbGYgaXMgZXZlbiBsb25nZXIhIChJdCB0YWtlcyBhIGxvdCBvZiBpbmZvcm1hdGlvbiB0byBtYWtlIGEgbWFwISkgTGV0J3MganVzdCBsb29rIGF0IHRoZSBgaGVhZGAgb2YgdGhpcyBkYXRhIGZvciBub3cKYGBge3J9CmhlYWQoT3V0cHV0LkFyZWFzKQpgYGAKCkhtbW1tLi4uIGRvZXNuJ3QgdGVsbCB1cyBtdWNoIDspIHlvdSBoYWQgYmV0dGVyIGV4cGxvcmUgaXQgaW4geW91ciBjb25zb2xlIChidXQgSSBhbSBub3QgZ29pbmcgdG8gZG8gdGhhdCBoZXJlIGJlY2F1c2UgaXQgd2lsbCBtYWtlIHVzIGFsbCBkbyB0b28gbXVjaCBzY3JvbGxpbmcgdG8gZ2V0IHBhc3QgaXQpLgoKVGhlIHdlaXJkIHN0cnVjdHVyZSB5b3UgZ2V0IG9jY3VycyBiZWNhdXNlIGBzcGAgb2JqZWN0cyBhcmUgc3RvcmVkIGFzIFM0IG9iamVjdHMgaW4gUi4gVGhpcyBpcyBhIHNwZWNpZmljIG9iamVjdCBvcmllbnRlZCBkYXRhIGZvcm1hdCwgd2hpY2ggaXMgcXVpdGUgY29tcGxleC4gWW91IGNhbiBmaW5kIG91dCBtb3JlIGFib3V0IGFsbCBvZiB0aGlzIGluIHRoaXMgZGF0YSBjYW1wIGNvdXJzZSBodHRwczovL3d3dy5kYXRhY2FtcC5jb20vY291cnNlcy93b3JraW5nLXdpdGgtZ2Vvc3BhdGlhbC1kYXRhLWluLXIgKHdoaWNoIGlzIHF1aXRlIGdvb2QhIEl0IGlzIGRlZmluaXRlbHkgd29ydGggeW91ciB3aGlsZSBsZWFybmluZyBhYm91dCBTNCBvYmplY3RzIGluIFIsIGFuZCB0aGlzIGlzIGEgZ29vZCB3YXkgdG8gZG8gaXQuKQoKT2suLi4gdGhpcyB0aGluZyBpcyBvZiBjbGFzcyAiU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIi4gVGhhdCBpcyBhIGNvbXBsZXggYmVhc3QhIChUcnkgcnVubmluZyA/U3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIHRvIGZpbmQgb3V0IGEgYml0IG1vcmUgYWJvdXQgKnRoZW0qLikgQSBjb29sIHRoaW5nIGFib3V0IHRoZXNlIG9iamVjdHMsIGlzIHRoYXQgdGhleSBoYXZlIGEgbmljZSBoYW5keSBwbG90IG1ldGhvZDoKCmBgYHtyfQpwbG90KE91dHB1dC5BcmVhcykKYGBgCgpJdHMgYSBtYXAgb2YgQ2FtYmRlbiEgKEkgZ3Vlc3Mgd2Ugc2hvdWxkIGhhdmUgZXhwZWN0ZWQgdGhhdCBnaXZlbiB0aGF0IHRoZSBmaWxlcyBhcmUgY2FsbGVkIENhbWJkZW5fKiA6fCAtIGhhdmUgYSBsb29rIGhlcmUgaWYgeW91IGRvbid0IGJlbGlldmUgbWU6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xvbmRvbl9Cb3JvdWdoX29mX0NhbWRlbikuIAoKSWYgeW91IHdhbnQgdG8gZmluZCBzb21lIEF1c3RyYWxpYW4gR0lTIGRhdGEgdGhlbiB5b3UgY291bGQgdHJ5IHRoZXNlIHNpdGVzOiAgIAotIGh0dHA6Ly93d3cubmF0dXJhbGVhcnRoZGF0YS5jb20vZG93bmxvYWRzLyAgIAotIGh0dHA6Ly9vcGVuc3RyZWV0bWFwZGF0YS5jb20vZGF0YSAKCk9rLi4uIHNvIHdlIGhhdmUgb3VyIG1hcC4gV2hhdCBjYW4gd2UgZG8gd2l0aCBpdD8gV2VsbC4uLiBpZiB3ZSBoYWQgc29tZSBkYXRhIHRoZW4gd2UgY291bGQgam9pbiBpdCB0byBvdXIgbWFwLi4uIFRoZW4gd2UgY291bGQgZG8gbG90cyBvZiBjb29sIHRoaW5ncyA7KQoKTHVja2lseSB0aGUgc2FtZSBzaXRlIG1ha2VzIGNlbnN1cyBkYXRhIGZvciB0aGUgVUsgYXZhaWxhYmxlIGluIGFuIGVhc3kgdG8gdXNlIGZvcm0uIFlvdSBjYW4gZG93bmxvYWQgaXQgaGVyZTogaHR0cHM6Ly9kYXRhLmNkcmMuYWMudWsvZGF0YXNldC9hYTU0OTFjOS1jYmFjLTQwMjYtOTdjOS1mOTE2ODQ2MmY0YWMvcmVzb3VyY2UvMjc5NDlkNTgtOGQ5Yi00M2IwLWIwZGQtZGZiZTQ3NjA5Y2JmL2Rvd25sb2FkL3ByYWN0aWNhbGRhdGEuY3N2IChkb24ndCBmb3JnZXQgdG8gcHV0IGl0IGluIHRoZSByaWdodCBwbGFjZSBzbyB0aGF0IFIgY2FuIGZpbmQgaXQpOgoKYGBge3J9CkNlbnN1cy5EYXRhIDwtcmVhZC5jc3YoInByYWN0aWNhbGRhdGEuY3N2IikKYGBgCgooSGF2ZSBhIGxvb2sgYSB0aGUgZGF0YSEgV2hhdCBpcyBpbiB0aGVyZT8pCgpPay4gSG93IGRvIHdlIGpvaW4gaXQ/IFdlIHVzZSBhIGBtZXJnZWAgZnVuY3Rpb24gdGhhdCBjb21lcyB3aXRoIHRoZSBgc3BgIHBhY2thZ2U6CgpgYGB7cn0KT0EuQ2Vuc3VzIDwtIG1lcmdlKE91dHB1dC5BcmVhcywgQ2Vuc3VzLkRhdGEsIGJ5Lng9Ik9BMTFDRCIsIGJ5Lnk9Ik9BIikKYGBgCgooTWFrZSBzdXJlIHlvdSBsb29rIHVwIHdoYXQgSSBkaWQgdGhlcmUgdXNpbmcgdGhlIGhlbHBmaWxlLi4uIGluIHBhcnRpY3VsYXIgLSBjYW4geW91IHdvcmsgb3V0IHdoYXQgaXMgZ29pbmcgb24gd2l0aCB0aG9zZSBgYnkueGAgYW5kIGBieS55YCBvcHRpb25zPykKCk9rLi4uIG5vIGVycm9ycyBzbyBpdCBsb29rcyBsaWtlIHRoZSBkYXRhIG1lcmdlZCBwcm9wZXJseS4gTm93IHdoYXQgZG8gd2UgaGF2ZT8KCmBgYHtyfQpoZWFkKE9BLkNlbnN1cykKYGBgCgpPb29vLi4uIGl0IGlzIG9uZSBvZiB0aG9zZSBTUGRhdGFmcmFtZSB0aGluZ29zIHdpdGggNSB2YXJpYWJsZXMgbm93ICh0cnkgbG9va2luZyBhdCBgT0EuQ2Vuc3VzYCBhbmQgYE91dHB1dC5BcmVhc2AgaW4geW91ciBFbnZpcm9ubWVudCB0YWIgb24gdGhlIHJpZ2h0IHRvIHdvcmsgb3V0IHdoYXQgaXMgZGlmZmVyZW50IGJldHdlZW4gdGhlIHR3byBgc3BgIG9iamVjdHMgLSB3aGF0IGhhcyBoYXBwZW5lZD8pIAoKQmFzaWNhbGx5Li4uIHdlIGhhdmUgYWRkZWQgc29tZSBkYXRhIHRvIG91ciBtYXAhIDUgbmV3IHZhcmlhYmxlcyBhcmUgbm93IGluIHRoZXJlIGFib3V0IHRoZSBudW1iZXIgb2YgV2hpdGVfQnJpdHRpc2ggY2l0aXplbnMgdGhlcmUgYXJlIGluIGFuIGFyZWEsIHRoZSBMb3dfT2NjdXBhbmN5IGluZm8sIGhvdyBtYW55IFVuZW1wbG95ZWQsIGFuZCB0aGVpciBRdWFsaWZpY2F0aW9uLiBHbyBhbmQgbG9vayBhdCB0aGUgc2l0ZSB3ZSBnb3QgdGhlIGRhdGEgZnJvbSB0byBmaW5kIG91dCBtb3JlIGFib3V0IHRoaXMgZGF0YXNldCAoUHJhY3RpY2FsIDEgaGFzIGluZm9ybWF0aW9uIGFib3V0IHdoZXJlIHRoZSBkYXRhIGNvbWVzIGZyb206IGh0dHBzOi8vZGF0YS5jZHJjLmFjLnVrL2RhdGFzZXQvYWE1NDkxYzktY2JhYy00MDI2LTk3YzktZjkxNjg0NjJmNGFjL3Jlc291cmNlLzA5YTEwOTNhLTc0YjktNDg3Yi1hOTM5LWQ5MjhmMjdiZTYxMi9kb3dubG9hZC9wcmFjdGljYWwxLmh0bWwpLiAKCk5vdy4gTWFueSBkaWZmZXJlbnQgY29vcmRpbmF0ZSBzeXN0ZW1zIGFyZSBwb3NzaWJsZS4gSWYgeW91IGFyZSBoYXZpbmcgdHJvdWJsZSB1c2luZyBHSVMgZGF0YSB0aGlzIGNvdWxkIHdlbGwgYmUgd2hhdCBpcyBnb2luZyB3cm9uZy4gSGVyZSwgd2UgYXJlIGdvaW5nIHRvIHNldCB0aGUgY29vcmRpbmF0ZSBzeXN0ZW0gdG8gdGhlIEJyaXRpc2ggTmF0aW9uYWwgR3JpZCAod2hpY2ggaXMgdGhlIGZvcm1hdCB0aGUgZGF0YSBhY3R1YWxseSBjYW1lIGluIC0gd2UgYXJlIGp1c3QgbWFraW5nIHN1cmUsIGFuZCBpdCBpcyBhbiBpbXBvcnRhbnQgdGhpbmcgdG8gbGVhcm4gYWJvdXQpOgoKYGBge3J9CnByb2o0c3RyaW5nKE9BLkNlbnN1cykgPC0gQ1JTKCIraW5pdD1FUFNHOjI3NzAwIikKYGBgCgpDb29sLiBBIHJlYWxseSBnb29kIHBsYWNlIHRvIGdvIGlmIHlvdSB3YW50IHRvIGxlYXJuIG1vcmUgYWJvdXQgbWFwcGluZyAoYXMgd2VsbCBhcyBzb21lIG9mIHRoZSBSIFM0IGNsYXNzZXMgbGlrZSBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUgYW5kIGhvdyB0aGV5IHdvcmshKSBpcyB0aGlzIGRhdGEgY2FtcCBjb3Vyc2U6IGh0dHBzOi8vY2FtcHVzLmRhdGFjYW1wLmNvbS9jb3Vyc2VzL3dvcmtpbmctd2l0aC1nZW9zcGF0aWFsLWRhdGEtaW4tci4gCkNoYXB0ZXJzIDIgb253YXJkcyBhcmUgdmVyeSBuaWNlLCBhbmQgcHJvdmlkZSBhIGdvb2QgaW50cm9kdWN0aW9uIHRvIHRoZSBgc3BgLCBgcmFzdGVyYCBhbmQgYHJnZGFsYCBwYWNrYWdlcywgc2V0dGluZyBjb29yZGluYXRlIHN5c3RlbXMgZXRjLiBJIHN0cm9uZ2x5IHJlY29tbWVuZCB3b3JraW5nIHRocm91Z2ggdGhpcyBjb3Vyc2UgaWYgeW91IHdhbnQgdG8gZmluZCBvdXQgbW9yZSBhYm91dCB3aGF0IHdlIGFyZSBkb2luZyBoZXJlICh3ZSBhcmUgc2tpbW1pbmcgdGhyb3VnaCEpCgpOb3cuLi4gd2UgY291bGQgbWFrZSBvdXIgbWFwIGxvb2sgbmljZXIuIExldCdzIHVzZSB0aGUgYHRtYXBgIHBhY2thZ2UsIHdoaWNoIHdvcmtzIHF1aXRlIGEgYml0IGxpa2UgZ2dwbG90IChpLmUuIGl0IGxheWVycyB0aGUgZ3JhcGhpY3MgdXAsIHNvIGlzIHF1aXRlIHBvd2VyZnVsKS4KCmBgYHtyfQpsaWJyYXJ5KHRtYXApCmBgYAoKSGF2ZSBhIGxvb2sgYXQgYD90bV9zaGFwZWAgYW5kIGA/dG1fZmlsbGAgYW5kIHlvdSB3aWxsIHN0YXJ0IHdvcmtpbmcgb3V0IGhvdyBpdCBjYW4gYmUgdXNlZC4gRm9yIGEgbGlzdCBvZiBhbGwgcG9zc2libGUgZnVuY3Rpb25zIHRyeSBgP3RtYXBgLiBUaGF0IERhdGEgQ2FtcCBjb3Vyc2UgSSBtZW50aW9uZWQgYWJvdmUgIChodHRwczovL2NhbXB1cy5kYXRhY2FtcC5jb20vY291cnNlcy93b3JraW5nLXdpdGgtZ2Vvc3BhdGlhbC1kYXRhLWluLXIpIGlzIHRoZSBwbGFjZSB0byBnbyBpZiB5b3Ugd2FudCB0byBmaW5kIG91dCBtb3JlIGFib3V0IGhvdyBgdG1hcGAgd29ya3MuIFdlIGRvbid0IGhhdmUgdGltZSB0byBjb3ZlciBpdCBoZXJlLiAKCkxldCdzIHRyeSB1c2luZyBpdCEgV2hhdCBpcyB0aGUgc3ByZWFkIG9mIFF1YWxpZmljYXRpb25zIGFjb3JzcyBDYW1kZW4/CgpgYGB7cn0KdG1fc2hhcGUoT0EuQ2Vuc3VzKSArIHRtX2ZpbGwoIlF1YWxpZmljYXRpb24iKSAKYGBgCgpOaWNlIC0geW91IGNhbiBmaW5kIG91dCBhIGxvdCBtb3JlIGFib3V0IG1hcHBpbmcgb3B0aW9ucyBieSB3b3JraW5nIHRocm91Z2ggdGhlIHJlc3Qgb2YgUHJhY3RpY2FsIDUgb24gaHR0cHM6Ly9kYXRhLmNkcmMuYWMudWsvdHV0b3JpYWwvYW4taW50cm9kdWN0aW9uLXRvLXNwYXRpYWwtZGF0YS1hbmFseXNpcy1hbmQtdmlzdWFsaXNhdGlvbi1pbi1yICh3ZSBhcmUgZ29pbmcgdG8gbW92ZSBvbnRvIG1vcmUgc3RhdGlzdGljYWwgdGhpbmdzISkKCiMjI01vcmUgaW5mb3JtYXRpb24KCldlIGFyZSBub3QgZ29pbmcgdG8gY292ZXIgbWFwcGluZyBpbiBhbnkgbW9yZSBkZXRhaWwgLSB5b3UgY291bGQgZWFzaWx5IGNvbXBsZXRlIGEgd2hvbGUgY291cnNlIGp1c3QgaW4gdGhpcyEgRm9yIG1vcmUgaW5mb3JtYXRpb24geW91IGNvdWxkIHN0YXJ0IHdpdGggdGhlIGZvbGxvd2luZyB0d28gcmVzb3VyY2VzICh3aGljaCBJIGhhdmUgYWxyZWFkeSByZWZlcnJlZCB0byBhYm92ZSEpCgoqIGh0dHBzOi8vd3d3LmRhdGFjYW1wLmNvbS9jb3Vyc2VzL3dvcmtpbmctd2l0aC1nZW9zcGF0aWFsLWRhdGEtaW4tcgoqIGh0dHBzOi8vZGF0YS5jZHJjLmFjLnVrL3R1dG9yaWFsL2FuLWludHJvZHVjdGlvbi10by1zcGF0aWFsLWRhdGEtYW5hbHlzaXMtYW5kLXZpc3VhbGlzYXRpb24taW4tciAoUHJhY3RpY2FsIDUpCgoKIyNQb2ludCBQYXR0ZXJuIEFuYWx5c2lzCgpTby4uLiB3ZSBoYXZlIGEgbWFwLiBMZXQncyBwdXQgc29tZSBtb3JlIGRhdGEgb250byBpdC4gVGhlIHNhbWUgc2l0ZSBtYWtlcyBzb21lIHBvaW50IGRhdGEgYWJvdXQgaG91c2UgcHJpY2VzIGF2YWlsYWJsZSB2aWEgdGhpcyBsaW5rOiBodHRwczovL2RhdGEuY2RyYy5hYy51ay9kYXRhc2V0L2FhNTQ5MWM5LWNiYWMtNDAyNi05N2M5LWY5MTY4NDYyZjRhYy9yZXNvdXJjZS8yNGM0ZjUyNy00M2M4LTRjMDktODU1OC1hZDZhNDhlMTdkZTUvZG93bmxvYWQvY2FtZGVuaG91c2VzYWxlczE1LmNzdgoKTGV0J3MgbG9vayBhdCBpdCAobWFrZSBzdXJlIHlvdSBhaHZlIGRvd25sb2FkZWQgdGhlIGRhdGEgZnJvbSB0aGUgc2l0ZSEgWW91IHdpbGwgbmVlZCB0byBsb2cgaW4gdG8gYWNjZXNzIGl0IHdoaWNoIGlzIHdoeSB3ZSBhcmUgbm90IGJvdGhlcmluZyB0byByZWFkIGl0IGRpcmVjdGx5KToKCmBgYHtyfQpob3VzZXMgPC0gcmVhZC5jc3YoIkNhbWRlbkhvdXNlU2FsZXMxNS5jc3YiKQpob3VzZXMKYGBgCgpSaWdodC1vLiBXZSBoYXZlIHNlZW4gdGhpbmdzIGxpa2UgdGhpcyBiZWZvcmUuIExldCdzIHF1aWNrbHkgcGxvdCBvdXQgd2hhdCBsb29rcyBsaWtlIHRoZSBsYXR0aXR1ZGUvbG9uZ2l0dWRlIGRhdGE6CgpgYGB7cn0KcGxvdChob3VzZXMkb3NlYXN0MW0sIGhvdXNlcyRvc25ydGgxbSkKYGBgCgpZZXAgLSBpdCBhbHNvIGxvb2tzIGxpa2UgQ2FtYmRlbiEgV2UgY2FuIHByb2JhYmx5IGp1c3QgbWFwIHRoZSB0d28gZGF0YXNldHMgdG9nZXRoZXIuIElmIHdlIHR1cm4gdGhpcyBvYmplY3QgKHdoaWNoIGlzIGp1c3QgYSBkYXRhZnJhbWUpIGludG8gYSBTcGF0aWFsUG9pbnRzRGF0YUZyYW1lIChsaWtlIE9BLkNlbnN1cykgdGhlbiB3ZSB3aWxsIGJlIGFibGUgdG8gbGF5ZXIgdGhlbSBvbiBvbmUgYW5vdGhlciEgV2UgbmVlZCB0byBiZSBhIGJpdCBjYXJlZnVsIGFib3V0IHRoYXQgY29vcmRpbmF0ZSBmcmFtZSB0aGluZyBhZ2FpbiB0aG91Z2ggKGkuZS4gd2UgbmVlZCB0byBzZXQgaXQgYWdhaW4pLiAKClNvLiBXZSBuZWVkIHRvIHNldCB3aGF0IHRoZSBkYXRhIGlzIHRvIGJlIGluY2x1ZGVkIChgaG91c2VzYCksIHdoYXQgY29sdW1ucyBjb250YWluIHRoZSB4IGFuZCB5IGNvb3JkaW5hdGVzIChgaG91c2VzWywzOjRdYCksIGFuZCB3aGF0IHByb2plY3Rpb24gc3lzdGVtIHdlIGFyZSB1c2luZyAoYENSUygiK2luaXQ9RVBTRzoyNzcwMCIpYCkuCgpgYGB7cn0KSG91c2UuUG9pbnRzIDwtU3BhdGlhbFBvaW50c0RhdGFGcmFtZShob3VzZXNbLDg6OV0sIGhvdXNlcywgcHJvajRzdHJpbmcgPSBDUlMoIitpbml0PUVQU0c6Mjc3MDAiKSkKYGBgCgpMZXQncyBwcmludCBpdCBqdXN0IHRvIGJlIHN1cmU6CgpgYGB7cn0KSG91c2UuUG9pbnRzCmBgYAoKCmBgYHtyfQojIGNyZWF0ZXMgYSBjb2xvdXJlZCBkb3QgbWFwCnRtX3NoYXBlKE9BLkNlbnN1cykgKyB0bV9ib3JkZXJzKGFscGhhPS40KSArCnRtX3NoYXBlKEhvdXNlLlBvaW50cykgKyB0bV9kb3RzKGNvbCA9ICJQcmljZSIsIHBhbGV0dGUgPSAiUmVkcyIsIHN0eWxlID0gInF1YW50aWxlIikgCmBgYAoKQWxyaWdodCEgVGhhdCdzIGtpbmQgb2YgbmljZSEgQWdhaW4uIFlvdSBjYW4ga2VlcCBnb2luZywgYW5kIGFkZGluZyB0byB0aGlzIG1hcCBpZiB5b3UgY2hlY2sgb3V0IFByYWN0aWNhbCA2IG9mIGh0dHBzOi8vZGF0YS5jZHJjLmFjLnVrL3R1dG9yaWFsL2FuLWludHJvZHVjdGlvbi10by1zcGF0aWFsLWRhdGEtYW5hbHlzaXMtYW5kLXZpc3VhbGlzYXRpb24taW4tciwgd2UgYXJlIGdvaW5nIHRvIG1vdmUgb250byBLZXJuZWwgc21vb3RoaW5nIQoKCgojIyMgS2VybmVsIHNtb290aGluZwoKCkEgcG9pbnQgcGF0dGVybiBpcyByZWFsbHkganVzdCBhIGNvbGxlY3Rpb24gb2YgZ2VvZ3JhcGhpY2FsIHBvaW50cywgdGhhdCBhcmUgYXNzdW1lZCB0byBiZSBnZW5lcmF0ZWQgYnkgYSByYW5kb20gcHJvY2Vzcy4gTGV0J3MgaW1hZ2luZSB0aGUgc2VyaWVzIG9mIHBvaW50cyBpbiBhbiAkKHgseSkkIGNvb3JkaW5hdGUgc3lzdGVtLCB0aGVuIHdlIGNhbiBpbWFnaW5lIHRoZSB2ZWN0b3Igb2YgJG4kIG9ic2VydmF0aW9uczoKJHtcYmZ7eH1faX09XHsoeF8xLCB5XzEpLCAoeF8yLHlfMilcZG90cywgKHhfbix5X24pXH0kIGZvciBzb21lIHZhcmlhYmxlIG9mIGludGVyZXN0LiAKCk9uZSB3YXkgdG8gYW5hbHlzZSB0aGVzZSB0eXBlIG9mIHBvaW50IGRpc3RyaWJ1dGlvbnMgaXMgdG8gcGVyZm9ybSBrZXJuZWwgc21vb3RoaW5nLCB3aGVyZSB5b3UgcmVwbGFjZSBlYWNoIHBvaW50ICR4X2kkIHdpdGggYSAqa2VybmVsKiwgd2hpY2ggaXMganVzdCBhIHNpbXBsZSBsb2NhbGlzZWQgZnVuY3Rpb24gJGYoe1xiZiB4X2l9KSQgY2VudHJlZCBvbiBlYWNoIG9mIG91ciBwb2ludHMuIFdlIGNhbiB0aGVuIGFuZCBhZGQgdXAgYWxsIHRoZXNlIGtlcm5lbHMgdG8gZ2V0IGEgc21vb3RoIGludGVuc2l0eSBmdW5jdGlvbiwgd2hpY2ggZGVzY3JpYmVzIGhvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIHBvaW50cyBiZWhhdmVzIG92ZXIgc3BhY2UuIFlvdSBjb3VsZCByZWFsbHkganVzdCB0aGluayBvZiB0aGlzIGFzIGEgImJ1bXAgYXZlcmFnaW5nIHByb2Nlc3MiLiAKClRvIHZpc3VhbGlzZSB0aGlzIHByb2Nlc3MsIGltYWdpbmUgdGhhdCB5b3UgaGF2ZSBzb21lIGJsb3R0ZXIgcGFwZXIsIGFuZCB5b3UgYXJlIHB1dHRpbmcgIGEgZG90IG9mIGluayBhdCBlYWNoIHBvaW50IG92ZXIgeW91ciBwYXBlci4gVGhlIGluayB3aWxsIHNwcmVhZCBvdXQsIHdpdGggYSBkYXJrZXIgc3BvdCBpbiB0aGUgY2VudHJlLiBJZiB5b3UgZG8gdGhpcyBmb3IgYSBsb3Qgb2YgZGlmZmVyZW50IGRvdHMsIHRoZW4gdGhleSB3aWxsIHN0YXJ0IHRvIG92ZXJsYXAsIGdldHRpbmcgZGFya2VyLiBUaGF0IGlzIHlvdXIgaW50ZW5zaXR5IGZ1bmN0aW9uIQoKWW91IG5lZWQgdG8gZGVjaWRlIHRoaW5ncyBsaWtlIHdoYXQgdHlwZSBvZiBrZXJuZWwgZnVuY3Rpb24gdG8gdXNlLCB3aGF0IHNoYXBlIGl0IGhhcyBldGMuIGJ1dCB0aGUgZGVuc2l0eSBmdW5jdGlvbiBpbiBgc3BhdHN0YXRgIGhhcyBzb21lIHByZXR0eSBnb29kIG9uZXMgZm9yIHlvdSB0byB1c2UgaWYgeW91IG5lZWQgc29tZXRoaW5nIGRpZmZlcmVudC4gKFRoaXMgZGF0YSBjYW1wIGNvdXJzZSBnaXZlcyBhIGdvb2QgaW50cm9kdWN0aW9uOiBodHRwczovL2NhbXB1cy5kYXRhY2FtcC5jb20vY291cnNlcy9zcGF0aWFsLXN0YXRpc3RpY3MtaW4tci8pLiBIZXJlLCB3ZSBhcmUgZ29pbmcgdG8gdXNlIGEgbW9yZSBtb2Rlcm4gcGFja2FnZSB0aGF0IGNvdXBsZXMgdmVyeSBuaWNlbHkgd2l0aCBvdXIgdG1hcCBvYmplY3QuIAoKVGhlIGBrZXJuZWxVRGAgZnVuY3Rpb24gcnVucyBhIHN0cmFpZ2h0Zm9yd2FyZCBlc3RpbWF0aW9uIG9mIG91ciBob3VzZSBwcmljZSBkYXRhOgoKYGBge3J9CmxpYnJhcnkoYWRlaGFiaXRhdEhSKQojIHJ1bnMgdGhlIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24sbG9vayB1cCB0aGUgZnVuY3Rpb24gcGFyYW1ldGVycyBmb3IgbW9yZSBvcHRpb25zCmtkZS5vdXRwdXQgPC0ga2VybmVsVUQoSG91c2UuUG9pbnRzLCBoPSJocmVmIiwgZ3JpZCA9IDEwMDApCnBsb3Qoa2RlLm91dHB1dCkKYGBgCgpJbnRlcmVzdGluZy4gQ2FuIHdlIHB1dCBpdCBvbiBvdXIgbWFwPyBGaXJzdCB3ZSBoYXZlIHRvIGNvbnZlcnQgaXQgdG8gYSBgcmFzdGVyYCBvYmplY3QsIGFuZCBzZXQgaXRzIGNvb3JkaW5hdGUgc3lzdGVtLCBzbyB0aGF0IHdlIGNhbiB0aGVuIG1hcCBpdCBvbnRvIG91ciBwcmV2aW91cyBtYXA6CgpgYGB7cn0KbGlicmFyeShyYXN0ZXIpCiNjb252ZXJ0IG91ciBrZXJuZWwgZGVuc2l0eSBtYXAgdG8gYSByYXN0ZXIgb2JqZWN0CmtkZSA8LSByYXN0ZXIoa2RlLm91dHB1dCkKIyBzZXQgdGhlIGNvb3JkaW5hdGUgcHJvamVjdGlvbiBvZiBvdXIgb2JqZWN0IHRvIEJyaXRpc2ggTmF0aW9uYWwgR3JpZCAodGhlIG9uZSB3ZSBoYXZlIGJlZW4gdXNpbmcgYWxsIGFsb25nKQpwcm9qZWN0aW9uKGtkZSkgPC0gQ1JTKCIraW5pdD1FUFNHOjI3NzAwIikKI21hcCBpdCEKdG1fc2hhcGUoa2RlKSArIHRtX3Jhc3RlcigidWQiKQpgYGAKCldlIGNhbiB6b29tIGluIHRvIG1hdGNoIGl0IHRvIG91ciBwcmV2aW91cyBtYXAgKGlmIHlvdSBoYXZlIGZvcmdvdHRlbiB3aGF0IHRoYXQgd2FzIHRoZW4gZ28gYmFjayB1cCBhbmQgcmVtaW5kIHlvdXJzZWxmIG9mIHdoYXQgdGhlIGBPdXRwdXQuQXJlYXNgIG1hcCB3YXMhKQoKYGBge3J9Cm1hc2tlZF9rZGUgPC0gbWFzayhrZGUsIE91dHB1dC5BcmVhcykKcGxvdChtYXNrZWRfa2RlKSAjIGEgcXVpY2sgc2FuaXR5IGNoZWNrIQpgYGAKKFRoZXJlIGlzIG5vcm1hbGx5IGEgZ29vZCBiZXQgdGhhdCB0aGUgYHBsb3RgIGZ1bmN0aW9uIHdpbGwgZXhpc3QgZm9yIHRoaW5ncyBvZiB0aGVzZSB0eXBlLCBzbyBpdCBpcyB3b3J0aCBhIHRyeSBpZiB5b3UgZG9uJ3Qga25vdyB3aGF0IHRvIGRvIHdpdGggc29tZXRoaW5nLi4uIHRoYXQgaXMgcHJldHR5IG11Y2ggd2hhdCB3ZSBkaWQgaGVyZSA7KQoKTmljZSEgTG9va3MgbGlrZSB0aGluZ3MgYXJlIHdvcmtpbmcuLi4gTGV0J3MgbmVhdGVuIGl0IHVwIGEgYml0IHdpdGggc29tZSBvZiB0aGUgZnVuY3Rpb25hbGl0eSBidWlsdCBmb3IgYHRtYXBgISAKCmBgYHtyfQpsaWJyYXJ5KHRtYXB0b29scykgIyBwcm92aWRlcyBhIHNldCBvZiB0b29scyBmb3IgcHJvY2Vzc2luZyBzcGF0aWFsIGRhdGEKCiMgY3JlYXRlcyBhIGJvdW5kaW5nIGJveCBiYXNlZCBvbiB0aGUgZXh0ZW50cyBvZiB0aGUgT3V0cHV0LkFyZWFzIHBvbHlnb24gKHRvIG1ha2Ugb3VyIG1hcCBzbWFsbGVyKQpib3VuZGluZ19ib3ggPC0gYmIoT3V0cHV0LkFyZWFzKQoKIyBtYXBzIHRoZSByYXN0ZXIgd2l0aGluIHRoZSBib3VuZGluZyBib3gKdG1fc2hhcGUobWFza2VkX2tkZSwgYmJveCA9IGJvdW5kaW5nX2JveCkgKyB0bV9yYXN0ZXIoInVkIikKYGBgCgpCdXQgaWYgd2Ugd2FudCB0byBnZXQgc29tZXRoaW5nIG5pY2VyIHN0aWxsIHdlIGNhbiBrZWVwIG9uIGZpZGRsaW5nLi4uIEkgd2lsbCBsZWF2ZSBpdCBmb3IgeW91IHRvIGxvb2sgdXAgYWxsIHRoZSBjYWxscyBpbiB0aGUgaGVscCEKCmBgYHtyfQp0bV9zaGFwZShtYXNrZWRfa2RlLCBiYm94ID0gYm91bmRpbmdfYm94KSArIHRtX3Jhc3RlcigidWQiLCBzdHlsZSA9ICJxdWFudGlsZSIsIG4gPSAxMDAsIGxlZ2VuZC5zaG93ID0gRkFMU0UsIHBhbGV0dGUgPSAiWWxHbkJ1IikgKwp0bV9zaGFwZShPdXRwdXQuQXJlYXMpICsgdG1fYm9yZGVycyhhbHBoYT0uMywgY29sID0gIndoaXRlIikgKwp0bV9sYXlvdXQoZnJhbWUgPSBGQUxTRSkKYGBgCgpOaWNlISBUaGF0IHRlbGxzIHVzIGEgbG90IGFib3V0IGhvdyBob3VzZSBwcmljZXMgYXJlIGNoYW5naW5nIGFzIHdlIG1vdmUgYXJvdW5kIGluIENhbWRlbi4gKEFueSBncm91cHMgdGhpbmsgdGhhdCBraW5kIG9mIHRoaW5nIG1pZ2h0IGJlIHVzZWZ1bD8gOykKCiMjI01vcmUgaW5mb3JtYXRpb24KCiogUHJhY3RpY2FsIDggb2YgaHR0cHM6Ly9kYXRhLmNkcmMuYWMudWsvdHV0b3JpYWwvYW4taW50cm9kdWN0aW9uLXRvLXNwYXRpYWwtZGF0YS1hbmFseXNpcy1hbmQtdmlzdWFsaXNhdGlvbi1pbi1yCiogQSB2ZXJ5IGRldGFpbGVkIG9ubGluZSBib29rOiBodHRwOi8vd3d3LnNwYXRpYWxhbmFseXNpc29ubGluZS5jb20vSFRNTC9pbmRleC5odG1sP2ludHJvZHVjdGlvbl9hbmRfdGVybWlub2xvZ3kuaHRtCiogaHR0cHM6Ly9jYW1wdXMuZGF0YWNhbXAuY29tL2NvdXJzZXMvc3BhdGlhbC1zdGF0aXN0aWNzLWluLXIvIEEgZGF0YSBjYW1wIGNvdXJzZSB0aGF0IGhhcyBzb21lIGdvb2QgcHJhY3RpY2UgZXhlcmNpc2VzLCBhbHRob3VnaCBJIGZpbmQgaXQgYSBiaXQgbG9uZ3dpbmRlZCBpbiBzb21lIG9mIHRoZSBleGFtcGxlcy4gCiogQ2hhcHRlciA2IG9mIEJydW5zZG9uLCBDLiwgJiBDb21iZXIsIEwuICgyMDE1KS4gQW4gaW50cm9kdWN0aW9uIHRvIFIgZm9yIHNwYXRpYWwgYW5hbHlzaXMgYW5kIG1hcHBpbmcuIFNhZ2UuIChBdmFpbGFibGUgaW4gbGlicmFyeTogaHR0cDovL2ZpbmQubGliLnV0cy5lZHUuYXUvP1I9T1BBQ19iMjkxNDI5NCkKCgojI1NwYXRpYWwgQXR0cmlidXRlIEFuYWx5c2lzCgpRdWl0ZSBvZnRlbiB3ZSBnZXQgZGF0YSBpbiByZWdpb25zIChlLmcuIExHQSwgU0E0IGV0Yy4pIGluc3RlYWQgb2YgYXMgYSBwb2ludCBmdW5jdGlvbi4gVGhpcyBpcyBzbyBjb21tb24gdGhhdCB0aGVyZSBhcmUgYSB3aG9sZSByYW5nZSBvZiB0ZWNobmlxdWVzIGZvciBkZWFsaW5nIHdpdGggaXQuIAoKIyMjU3BhdGlhbCBBdXRvY29ycmVsYXRvbgoKU3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgYW4gZXh0ZW5zaW9uIG9mIHRlbXBvcmFsIGF1dG9jb3JyZWxhdGlvbiAod2hpY2ggaXMgY292ZXJlZCBpbiB0aGUgd29ya2Jvb2sgb24gVGltZSBTZXJpZXMpLiBJdCBpcyBhIGJpdCBtb3JlIGNvbXBsZXggdGhvdWdoLCBhcyBzcGF0aWFsIG9iamVjdHMgIGhhdmUgKGF0IGxlYXN0KSB0d28gZGltZW5zaW9ucyBhbmQsIGxpa2Ugd2UgaGF2ZSBzZWVuIGFib3ZlLCB0aGUgcmVnaW9ucyBjYW4gaGF2ZSBjb21wbGV4IHNoYXBlcy4gVGhpcyBtZWFucyB0aGF0IGl0IG1heSBub3QgYmUgb2J2aW91cyBob3cgdG8gZGV0ZXJtaW5lIHdoYXQgaXMgIm5lYXIiLCBhbmQgdGhlcmUgYXJlIGxvdHMgb2YgZGlmZmVyZW50IG1lYXN1cmVzIG9mIHRoaXMgKHdlIGFyZSBqdXN0IGdvaW5nIHRvIGNvbnNpZGVyIG9uZSwgYnV0IHlvdSB3aWxsIGZpbmQgbG90cyBvZiByZXNvdXJjZXMgYWJvdXQgb3RoZXIgbWV0aG9kcyBhcyB5b3Ugd29yayB0aHJvdWdoIHRoaXMgc2VjdGlvbikuCgpBIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIG1lYXN1cmVzIGhvdyBkaXN0YW5jZSBpbmZsdWVuY2VzIGEgcGFydGljdWxhciB2YXJpYWJsZS4gQmFzaWNhbGx5LCB3ZSBleHBlY3QgdGhpbmdzIHRoYXQgYXJlIGNsb3NlIHRvZ2V0aGVyIHRvIGJlIHNpbWlsYXIuIFNvIGZvciBleGFtcGxlLCBhIGNvbnRhZ2lvdXMgZGlzZWFzZSBpcyBtb3JlIGxpa2VseSB0byBzcHJlYWQgdG8gcGVvcGxlIHdobyBsaXZlIGNsb3NlIHRvIGVhY2ggb3RoZXIsIG9yIHBlb3BsZSB0ZW5kIHRvIGNsdXN0ZXIgdG9nZXRoZXIgaW4gc3VidXJicyB3aXRoIHBlb3BsZSBsaWtlIHRoZW0uIENhbiB3ZSB0aGluayBvZiBhIHZhcmlhYmxlIHRoYXQgbWlnaHQgZG8gdGhpcyBpbiBvdXIgZGF0YXNldD8gV2hhdCBhYm91dCBxdWFsaWZpY2F0aW9ucz8gWW91IG1pZ2h0IGV4cGVjdCB0aGF0IHN1YnVyYnMgd2l0aCBhIGxvdCBvZiBwZW9wbGUgd2l0aCBkZWdyZWVzIHdpbGwgdGVuZCB0byBjbHVzdGVyIHRvZ2V0aGVyIHBlcmhhcHMuLi4gCgogTGV0J3MgZ28gYmFjayB0byBvdXIgbWFwLCBhbmQgYWRqdXN0IGl0IGEgYml0IHRvIHNlZSBpZiB0aGlzIG1pZ2h0IGJlIG9jY3VycmluZyBpbiBDYW1kZW4uIAoKYGBge3J9CnRtX3NoYXBlKE9BLkNlbnN1cykgKyB0bV9maWxsKCJRdWFsaWZpY2F0aW9uIiwgcGFsZXR0ZSA9ICJSZWRzIiwgc3R5bGUgPSAicXVhbnRpbGUiLCB0aXRsZSA9ICIlIHdpdGggYSBRdWFsaWZpY2F0aW9uIikgKyB0bV9ib3JkZXJzKGFscGhhPS40KSAgCmBgYAoKTG9va3MgbGlrZSB0aGlzIG1pZ2h0IGJlIGhhcHBlbmluZyBhY3R1YWxseS4gSG93IGNvdWxkIHdlIHRlc3Qgd2hldGhlciB0aGlzIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgdGhvdWdoPyBXZSB3aWxsIHVzZSB0aGUgYHNwZGVwYCBwYWNrYWdlIHRvIGxvb2sgYXQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIAoKYGBge3J9CmxpYnJhcnkoc3BkZXApCmBgYAoKRmlyc3QsIHdlIGhhdmUgdG8gZmluZCBvdXQgd2hpY2ggcG9seWdvbnMgaW4gb3VyIG1hcCBhcmUgbmVpZ2hib3VycyB3aXRoIG9uZSBhbm90aGVyLiBXZSBhcmUgZ29pbmcgdG8gdXNlIG9uZSBwYXJ0aWN1bGFyIG1ldGhvZCBoZXJlOgoKYGBge3J9Cm5laWdoYm91cnMgPC0gcG9seTJuYihPQS5DZW5zdXMsIHF1ZWVuID0gRkFMU0UpCm5laWdoYm91cnMKYGBgCgpCeSBzZXR0aW5nIGBxdWVlbiA9IEZBTFNFYCB3ZSBoYXZlIHNldCB1cCBvdXIgbWFwIHRvIHVzZSBhIGRlZmluaXRpb24gb2YgbmVpZ2hib3VycyB3aGVyZSBtb3JlIHRoYW4gb25lIHNoYXJlZCBwb2ludCBpcyByZXF1aXJlZCBmb3IgdHdvICByZWdpb25zIHRvIGJlIGRlZmluZWQgYXMgbmVpZ2hib3VyaW5nIG9uZSBhbm90aGVyLiAoTG9vayB1cCBtb3JlIG9wdGlvbnMgaW4gYD9wb2x5Mm5iYCBhbmQgeW91IGNhbiBmaW5kIG91dCBhIGxvdCBtb3JlIGRldGFpbHMgYWJvdXQgdGhpcyBpbiB0aGVzZSBzbGlkZXM6IGh0dHA6Ly93d3cuYmlhcy1wcm9qZWN0Lm9yZy51ay9BU0RBUmNvdXJzZS91bml0Nl9zbGlkZXMucGRmKS4KCldlIGNhbiBwbG90IHRoaXMgbGlzdCBvZiBuZWlnaGJvdXJzIG9uIG91ciBtYXAKCmBgYHtyfQpwbG90KE9BLkNlbnN1cywgYm9yZGVyID0gJ2xpZ2h0Z3JleScpCnBsb3QobmVpZ2hib3VycywgY29vcmRpbmF0ZXMoT0EuQ2Vuc3VzKSwgYWRkPVRSVUUsIGNvbD0ncmVkJykKYGBgCgpPay4gTm93IHdlIGNhbiBydW4gYW4gYXV0b3JlZ3Jlc3Npb24uIEZpcnN0IHdlIGhhdmUgdG8gY29udmVydCBvdXIgbmVpZ2hib3VycyBvYmplY3QgdG8gdGhlIHJpZ2h0IGtpbmQgb2YgZGF0YSBvYmplY3QsIG9uZSB0aGF0IGhhcyB3ZWlnaHRzOgoKYGBge3J9Cmxpc3R3IDwtIG5iMmxpc3R3KG5laWdoYm91cnMpCmxpc3R3CmBgYAoKQ29tcGFyZSBgbGlzdHdgIGFuZCBgbmVpZ2hib3Vyc2AuIFNlZSB0aGF0IG91ciBuZXcgbGlzdCBoYXMgZXh0cmEgaW5mb3JtYXRpb24gYWJvdXQgd2VpZ2h0cz8gV2UgaGF2ZSBzcGVjaWZpZWQgd2hhdCB0eXBlIG9mIGNvZGluZyBzY2hlbWUgd2UgYXJlIGdvaW5nIHRvIHVzZSwgdGhhdCBpcywgaG93IG5laWdoYm91cnMgd2l0aCBubyBsaW5rcyBzaG91bGQgYmUgdHJlYXRlZCBldGMuIFNlZSB0aGUgcHJlbGltaW5hcnkgZGV0YWlscyBhdCBgP25iMmxpc3R3YCwgYnV0IGlmIHlvdSB3YW50IHRvIGZpbmQgb3V0IG1vcmUgYWJvdXQgdGhpcyBwcm9jZXNzIHRoZW4geW91IGNvdWxkIGNoZWNrIG91dCBzbGlkZXMgMjMtMjYgb2YgdGhpcyBzZXQ6IGh0dHA6Ly93d3cuYmlhcy1wcm9qZWN0Lm9yZy51ay9BU0RBUmNvdXJzZS91bml0Nl9zbGlkZXMucGRmIChMb3RzIG9mIG90aGVyIGRldGFpbHMgaW4gaGVyZSB0b28hKQoKT2suIFdlIGNhbiBub3cgcnVuIGEgdGVzdCBmb3Igc3BhdGlhbCBhdXRvY29ycmVsYXRpb24hIFdlIGFyZSBnb2luZyB0byB1c2UgTW9yYW4ncyB0ZXN0LCB3aGljaCBjcmVhdGVzIGEgY29ycmVsYXRpb24gc2NvcmUgYmV0d2VlbiAtMSBhbmQgMS4gCkhhdmUgYSBsb29rIGF0IGA/bW9yYW5gIHRvIGZpbmQgb3V0IG1vcmUgYWJvdXQgTW9yYW4ncyBJIHdvcmtzLCBidXQgYmFzaWNhbGx5IGl0IG1lYXN1cmVzIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGJhc2VkIG9uIGJvdGggZmVhdHVyZSBsb2NhdGlvbnMgYW5kIGZlYXR1cmUgdmFsdWVzIHNpbXVsdGFuZW91c2x5LiAoU2VlIHRoZSB3aWtpcGVkaWEgcGFnZSBmb3IgYSBiaXQgbW9yZSBpbmZvOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Nb3JhbiUyN3NfSSkgRW5vdWdoIGFscmVhZHkgLSBsZXRzIGRvIHRoZSB0ZXN0ISBBcmUgdGhlIHJlZ2lvbnMgYXV0b2NvcnJlbGF0ZWQ/CgpgYGB7cn0KbW9yYW4udGVzdChPQS5DZW5zdXMkUXVhbGlmaWNhdGlvbiwgbGlzdHcpCmBgYAoKT2suIE91ciBwLXZhbHVlIGlzIHNpZ25pZmljYW50IGFuZCBvdXIgSSBzdGF0aXN0aWMgaXMgcG9zaXRpdmUgKGkuZSBjb3JyZWxhdGVkKS4gClNvIHRoZSByZWdpb25zIHNlZW0gdG8gYmUgc29tZXdoYXQgY29ycmVsYXRlZCwgYXMgd2UgZXhwZWN0ZWQgdG8gc2VlIGZyb20gdGhlIHJlZCBpbWFnZSBhYm92ZSB3aGVyZSB3ZSBzYXcgdGhhdCByZWdpb25zIHdpdGggbW9yZSBxdWFsaWZpY2F0aW9ucyB0ZW5kZWQgdG8gY2x1c3RlciB0b2dldGhlci4gVGhpcyBwYWdlIGhhcyBtb3JlIGRldGFpbHMgYWJvdXQgaW50ZXJwcmV0aW5nIE1vcmFuJ3MgSSwgYXRob3VnaCBpdCBpcyBmb3IgYSBkaWZmZXJlbnQgcGFja2FnZSBmcm9tIFI6IGh0dHA6Ly9oZWxwLmFyY2dpcy5jb20vZW4vYXJjZ2lzZGVza3RvcC8xMC4wL2hlbHAvaW5kZXguaHRtbCMvSG93X1NwYXRpYWxfQXV0b2NvcnJlbGF0aW9uX0dsb2JhbF9Nb3Jhbl9zX0lfd29ya3MvMDA1cDAwMDAwMDB0MDAwMDAwLwoKVGhpcyBpcyB3aGF0IGlzIGtub3duIGFzIGEgKmdsb2JhbCogYXV0b2NvcnJlbGF0aW9uIHRlc3QuIFdlIGFyZSBsb29raW5nIG92ZXIgdGhlIHdob2xlIG1hcCB0byBtZWFzdXJlIHNwYXRpYWwgY29ycmVsYXRpb24uIAoKV2UgY2FuIGFsc28gZG8gYSBsb2NhbCB0ZXN0IGZvciBhdXRvY29ycmVsYXRpb24uIExldCdzIHN0YXJ0IGJ5IGxvb2tpbmcgYXQgaG93IHRoZSBRdWFsaWZpY2F0aW9ucyBhcmUgY2hhbmdpbmcgYWdhaW5zdCAqc3BhdGlhbGx5KiBsYWdnZWQgdmFsdWVzLiAKSWYgeW91IHdhbnQgdG8gZmluZCBvdXQgbW9yZSBhYm91dCBob3cgdGhpcyB3b3JrcywgdGhlbiB0aGlzIHBhZ2UgaXMgYSBncmVhdCBwbGFjZSB0byBzdGFydDogaHR0cDovL3JzcGF0aWFsLm9yZy9hbmFseXNpcy9yc3QvMy1zcGF1dG8uaHRtbAoKYGBge3J9Cm1vcmFuIDwtIG1vcmFuLnBsb3QoT0EuQ2Vuc3VzJFF1YWxpZmljYXRpb24sIGxpc3R3ID0gbmIybGlzdHcobmVpZ2hib3Vycywgc3R5bGUgPSAiVyIpKQpgYGAKCkhtbW0uLi4gc2VlbXMgbGlrZSB0aGVyZSBtaWdodCBiZSBzb21lIHNvcnQgb2YgYSBwb3NpdGl2ZSByZWxhdGlvbnNoaXA/IFRoZXJlIGFyZSBxdWl0ZSBhIGZldyBvdXRsaWVycywgcGVyaGFwcyB3ZSBjYW4gbGVhcm4gYSBiaXQgbW9yZS4gVGhlIGBsb2NhbG1vcmFuYCBmdW5jdGlvbiBpcyB3aGF0IHdlIG5lZWQgKGNoZWNrIHRoZSBoZWxwIGZpbGUpCgpgYGB7cn0KbG9jYWwgPC0gbG9jYWxtb3Jhbih4ID0gT0EuQ2Vuc3VzJFF1YWxpZmljYXRpb24sIGxpc3R3ID0gbmIybGlzdHcobmVpZ2hib3Vycywgc3R5bGUgPSAiVyIpKQpoZWFkKGxvY2FsKQpgYGAKClJpZ2h0Li4uIHNvIHRoaXMgaXMgcHJvZHVjaW5nIGEgd2hvbGUgc2V0IG9mIHZhbHVlcyBmb3IgZWFjaCByZWdpb24hIFdlIGNvdWxkIGFkZCB0aGlzIHRvIG91ciBzaGFwZWZpbGUgYW5kIHRoZW4gd2Ugd291bGQgYmUgYWJsZSB0byBtYXAgaXQuLi4gCgpgYGB7cn0KIyBiaW5kcyByZXN1bHRzIHRvIG91ciBwb2x5Z29uIHNoYXBlZmlsZQptb3Jhbi5tYXAgPC0gY2JpbmQoT0EuQ2Vuc3VzLCBsb2NhbCkKCiMgbWFwcyB0aGUgcmVzdWx0cwp0bV9zaGFwZShtb3Jhbi5tYXApICsgdG1fZmlsbChjb2wgPSAiSWkiLCBzdHlsZSA9ICJxdWFudGlsZSIsIHRpdGxlID0gImxvY2FsIG1vcmFuIHN0YXRpc3RpYyIpIApgYGAKClNvIHRoaXMgc2hvd3MgdXMgdGhlIHZhcmlhdGlvbnMgaW4gYXV0b2NvcnJlbGF0aW9uIGFjcm9zcyBzcGFjZS4gQnV0IGFyZSB0aGV5IHNpZ25pZmljYW50PyBXZSBjb3VsZCB0cnkgbWFwcGluZyB0aGUgcC12YWx1ZXMgdGhlIHNhbWUgd2F5LiBGaXJzdCB3ZSBuZWVkIHRvIHdvcmsgb3V0IHdoYXQgdGhleSBhcmUgY2FsbGVkOgoKYGBge3J9Cm5hbWVzKG1vcmFuLm1hcEBkYXRhKQpgYGAKCgpgYGB7cn0KIyBtYXBzIHRoZSBwLXZhbHVlcwp0bV9zaGFwZShtb3Jhbi5tYXApICsgdG1fZmlsbChjb2wgPSAiUHIuei4uLjAuIiwgc3R5bGUgPSAiZml4ZWQiLCBicmVha3M9YygwLjAwMSwwLjAxLDAuMDUsMC4xLDAuMiwxKSwgdGl0bGUgPSAicC12YWx1ZXMiKSAKYGBgCgpJbnRlcmVzdGluZy4uLiBDYW4geW91IGludGVycHJldCB0aGlzPyBJcyBpdCB3aGF0IHlvdSBleHBlY3RlZD8gKE1ha2Ugc3VyZSB5b3UgbG9vayBhdCBib3RoIHRoZSBsb2NhbCBtb3JhbiBzdGF0aXN0aWNzIGFuZCB0aGUgcC12YWx1ZXMgaW4gaW50ZXJwcmV0aW5nIHlvdXIgcmVzdWx0cy4pCgpJbiBwcmFjdGljZSB5b3Ugc2hvdWxkIHJlYWxseSBiZSBjb21wYXJpbmcgdGhpcyB0byBhIHJhbmRvbWx5IGdlbmVyYXRlZCBNYXJrb3YgQ2hhaW4gYXBwcm9hY2guIFRoZSBEYXRhIENhbXAgY291cnNlIG9uIGh0dHBzOi8vY2FtcHVzLmRhdGFjYW1wLmNvbS9jb3Vyc2VzL3NwYXRpYWwtc3RhdGlzdGljcy1pbi1yLyBnb2VzIGludG8gdGhpcyBpbiBhIGxvdCBvZiBkZXRhaWwuIAoKIyMjI01vcmUgaW5mb3JtYXRpb24KCiogUHJhY3RpY2FsIDkgb2YgaHR0cHM6Ly9kYXRhLmNkcmMuYWMudWsvdHV0b3JpYWwvYW4taW50cm9kdWN0aW9uLXRvLXNwYXRpYWwtZGF0YS1hbmFseXNpcy1hbmQtdmlzdWFsaXNhdGlvbi1pbi1yIGlzIHZlcnkgYnJpZWYsIGFuZCBkb2VzIG5vdCBnbyBpbnRvIGEgbG90IG1vcmUgZGV0YWlscyB0aGFuIHdoYXQgd2UgaGF2ZSBjb3ZlcmVkLiBZb3Ugd291bGQgZG8gd2VsbCB0byB1c2Ugc29tZSBvZiB0aGUgZXh0cmEgcmVzb3VyY2VzIGJlbG93IGFzIHdlbGwgdG8gZmluZCBvdXQgbW9yZS4gCiogQSBuaWNlIHdvcmtib29rIG9uIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGh0dHA6Ly9yc3BhdGlhbC5vcmcvYW5hbHlzaXMvcnN0LzMtc3BhdXRvLmh0bWwKKiBBIHdob2xlIG9ubGluZSBib29rIG9uIEdlb3NwYXRpYWwgQW5hbHlzaXMsIHdoaWNoIGhhcyBhIHNlY3Rpb24gb24gc3BhdGlhbCBhdXRvY29ycmVsYXRpb246IGh0dHA6Ly93d3cuc3BhdGlhbGFuYWx5c2lzb25saW5lLmNvbS9IVE1MLz9zcGF0aWFsX2F1dG9jb3JyZWxhdGlvbi5odG0KKiBUaGlzIHNldCBvZiBzbGlkZXMgZ29lcyBpbnRvIGEgbG90IG1vcmUgZGV0YWlscyBhYm91dCB0aGUgdmFyaW91cyB3YXlzIG9mIGNhbGN1bGF0aW5nIGRpc3RhbmNlLCBob3cgdGhlIGBzcGRlcGAgZnVuY3Rpb25zIHdvcmsgZXRjLiBXb3J0aCBjaGVja2luZyBvdXQgaWYgeW91IHdhbnQgdG8ga25vdyBtb3JlOiBodHRwOi8vd3d3LmJpYXMtcHJvamVjdC5vcmcudWsvQVNEQVJjb3Vyc2UvdW5pdDZfc2xpZGVzLnBkZgoqIGh0dHBzOi8vY2FtcHVzLmRhdGFjYW1wLmNvbS9jb3Vyc2VzL3NwYXRpYWwtc3RhdGlzdGljcy1pbi1yLwoqIENoYXB0ZXIgNyBvZiBCcnVuc2RvbiwgQy4sICYgQ29tYmVyLCBMLiAoMjAxNSkuIEFuIGludHJvZHVjdGlvbiB0byBSIGZvciBzcGF0aWFsIGFuYWx5c2lzIGFuZCBtYXBwaW5nLiBTYWdlLiAoQXZhaWxhYmxlIGluIGxpYnJhcnk6IGh0dHA6Ly9maW5kLmxpYi51dHMuZWR1LmF1Lz9SPU9QQUNfYjI5MTQyOTQpCiogQSBzcGF0aWFsIGFuYWx5c2lzIGNvbXBsZXRlZCBieSBhIHBhc3QgU1REUyBzdHVkZW50IGZvciBBc3Nlc3NtZW50IDM6IGh0dHBzOi8vMTYtNjE0My5jYS51dHMuZWR1LmF1L3NwYXRpYWwtaW52ZXN0aWdhdGlvbi1vZi1ib20tZGF0YS1hc3N1bXB0aW9uLXVzZWQtaW4tZWFybGllci1hc3RobWEtaG9zcGlhdGxpc2F0aW9uLWludmVzdGlnYXRpb24vCgoKIyMjR2VvZ3JhcGhpY2FsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbgoKT2suLi4gZmluYWwgc3RlcCEgQ2FuIHdlIHdvcmsgb3V0IGhvdyB0byB1c2UgYXJlYXMgaW4gYSByZWdyZXNzaW9uIG1vZGVsPyBZZXMgd2UgY2FuISBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uIChHV1IpIGNhbiBiZSB1c2VkIHRvIGlkZW50aWZ5IGhvdyByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBtYXkgdmFyeSBhY3Jvc3MgdGhlIHN0dWR5IGFyZWEuIChTbyBpdCByZWxheGVzIGFzc3VtcHRpb25zIGFib3V0IHN0YXRpb25hcml0eSBmb3Igc3BhdGlhbCBkYXRhLikKCiMjIyNTdGFuZGFyZCBsaW5lYXIgcmVncmVzc2lvbiBvdmVyIGEgZ2VvZ3JhcGhpY2FsIGRhdGFzZXQKCkZpcnN0LCBsZXQncyB0cnkgcnVubmluZyBqdXN0IGEgbm9ybWFsIHJlZ3Jlc3Npb24gbW9kZWwsIHRoYXQgdHJpZXMgdG8gZXhwbGFpbiBRdWFsaWZpY2F0aW9ucyBpbiB0ZXJtcyBvZiB0aGUgb3RoZXIgdmFyaWFibGVzIGluIHRoZSBjZW5zdXMgZGF0YXNldDoKCmBgYHtyfQpsbS5tb2RlbCA8LSBsbShPQS5DZW5zdXMkUXVhbGlmaWNhdGlvbiB+IE9BLkNlbnN1cyRVbmVtcGxveWVkK09BLkNlbnN1cyRXaGl0ZV9Ccml0aXNoKQpzdW1tYXJ5KGxtLm1vZGVsKQpgYGAKCkl0cyBub3QgYSBiYWQgbW9kZWwuIEV4cGxhaW5zIDQ2LjUlIG9mIHRoZSB2YXJpYW5jZSwgZ29vZCBwLXZhbHVlcy4uLiB3aGF0IGRvIHRoZSByZXNpZHVhbHMgbG9vayBsaWtlPwoKYGBge3J9CnBsb3QobG0ubW9kZWwpCmBgYAoKTm90IGJyaWxsYW50LCBidXQga2luZCBvZiBvay4gSXMgdGhlcmUgYSBzcGF0aWFsIGRpc3RyaWJ1dGlvbiB0byB0aGVtIHRob3VnaD8gKFRoZXJlIHNob3VsZCBiZSAtIHdlIGp1c3QgZm91bmQgaXQgdXNpbmcgdGhlIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIHN0dWZmISkKCmBgYHtyfQpyZXNpZHM8LXJlc2lkdWFscyhsbS5tb2RlbCkKCm1hcC5yZXNpZHMgPC0gY2JpbmQoT0EuQ2Vuc3VzLCByZXNpZHMpIAojIHdlIG5lZWQgdG8gcmVuYW1lIHRoZSBjb2x1bW4gaGVhZGVyIGZyb20gdGhlIHJlc2lkcyBmaWxlIC0gaW4gdGhpcyBjYXNlIGl0cyB0aGUgNnRoIGNvbHVtbiBvZiBtYXAucmVzaWRzCm5hbWVzKG1hcC5yZXNpZHMpWzZdIDwtICJyZXNpZHMiCgojIG1hcHMgdGhlIHJlc2lkdWFscyB1c2luZyB0aGUgcXVpY2ttYXAgZnVuY3Rpb24gZnJvbSB0bWFwCnF0bShtYXAucmVzaWRzLCBmaWxsID0gInJlc2lkcyIpCgp0bV9zaGFwZShtYXAucmVzaWRzKSArIHRtX2ZpbGwoInJlc2lkcyIpIApgYGAKClNlZW1zIGxpa2UgdGhlcmUgbWlnaHQgYmUgYSBiaXQgb2YgYSBzcGF0aWFsIGRlcGVuZGVuY2UgdGhlcmUuIAoKIyMjIyNHV1IKCk9rLiBDYW4gd2UgdGFrZSBhY2NvdW50IG9mIHNwYXRpYWwgdmFyaWFibGVzIGFsb25nIHdpdGggb3VyIHJlZ3Jlc3Npb24gbW9kZWw/IEZpcnN0IHdlIG5lZWQgdG8gd29yayBvdXQgaG93IHRvIG1vZGVsIHRoZSBrZXJuZWwuIFdlIHdpbGwgdXNlIAoKYGBge3J9CmxpYnJhcnkoInNwZ3dyIikKCiNjYWxjdWxhdGUga2VybmVsIGJhbmR3aWR0aApHV1JiYW5kd2lkdGggPC0gZ3dyLnNlbChPQS5DZW5zdXMkUXVhbGlmaWNhdGlvbiB+IE9BLkNlbnN1cyRVbmVtcGxveWVkK09BLkNlbnN1cyRXaGl0ZV9Ccml0aXNoLCBkYXRhPU9BLkNlbnN1cyxhZGFwdD1UKQpgYGAKCk9rLiBOb3cgd2UgY2FuIHVzZSB0aGlzIHZhbHVlIG9mIHRoZSBiYW5kd2lkdGggaW4gb3VyIG1vZGVsIChkb24ndCBmb3JnZXQgdG8gbG9vayB1cCB0aGUgcmVsZXZhbnQgaGVscCBwYWdlcyB0byBmaW5kIG91dCB3aGF0IHdlIGFyZSBkb2luZyBoZXJlISkKCmBgYHtyfQojZml0IHRoZSBnd3IgbW9kZWwgKG5vdGUgaXQgaGFzIHRoZSBzYW1lIGZvcm11bGEgYXMgYmVmb3JlKQpnd3IubW9kZWwgPSBnd3IoT0EuQ2Vuc3VzJFF1YWxpZmljYXRpb24gfiBPQS5DZW5zdXMkVW5lbXBsb3llZCtPQS5DZW5zdXMkV2hpdGVfQnJpdGlzaCwgZGF0YSA9IE9BLkNlbnN1cywgYWRhcHQ9R1dSYmFuZHdpZHRoLCBoYXRtYXRyaXg9VFJVRSwgc2UuZml0PVRSVUUpIAoKI09LLiBXaGF0IGRpZCBpdCBkbz8KZ3dyLm1vZGVsCmBgYAoKU28uLi4gd2hhdCBoYXBwZW5lZD8gTGV0J3MgY29tcGFyZSBhIGZldyB0aGluZ3MuIEZpcnN0IC0gd2hhdCBhcmUgdGhlIGNvbXBvbmVudHMgb2YgdGhlIG1vZGVscz8KCmBgYHtyfQpuYW1lcyhsbS5tb2RlbCkKbmFtZXMoZ3dyLm1vZGVsKQpgYGAKCldoYXQgaWYgd2UgbG9vayBhdCB0aGUgY29lZmZpY2llbnRzIGZvciB0aGUgZ2xvYmFsIG1vZGVsIChpLmUuIHRoZSBzdGFuZGFyZCBsaW5lYXIgcmVncmVzc2lvbiBmaXQpIGFnYWluPwoKYGBge3J9CmxtLm1vZGVsJGNvZWZmaWNpZW50cwpgYGAKCkhvdyBkbyB0aGVzZSBjb21wYXJlIHdpdGggdGhlIHJhbmdlcyBvZiB0aGUgaW50ZXJjZXB0IGFuZCB0aGUgbW9kZWwgY29lZmZpY2llbnRzIGluIHRoZSBzdW1tYXJ5IGZvciBnd3IubW9kZWw/IFdoYXQgaGFzIGNoYW5nZWQgYnkgdXMgcnVubmluZyBhIGxvY2FsIHJlZ3Jlc3Npb24/IFRoZXkgYXJlIG5vdCBjb21wbGV0ZWx5IGRpZmZlcmVudCwgYnV0IGlmIHdlIGNvbXBhcmUgdGhlIE1lZGlhbiB2YWx1ZXMgdGhlbiB3ZSBzZWUgdGhhdCB0aGV5IGhhdmUgY2hhbmdlZCBhIGxpdHRsZSBiaXQuCgpUaGlzIGlzIGJlY2F1c2UgaW4gb3VyIEdXUiwgd2UgaGF2ZSBzZXRzIG9mIHRoZXNlIGludGVyY2VwdCBhbmQgY29lZmZpY2llbnQgdmFsdWVzIGZvciBlYWNoIG1hcCByZWdpb24gKGFsb25nIHdpdGggYSB3aG9sZSBoZWFwIG9mIGluZm9ybWF0aW9uIGFib3V0IHRoZSBlcnJvciBvZiB0aGUgZml0IGF0IHRoYXQgcG9pbnQpIC4gV2UgY2FuIGxvb2sgYXQgdGhlbSBlYXNpbHkgaWYgd2UgZm9yY2UgdGhlIHBhcnQgb2YgdGhlIG1vZGVsIHdpdGggdGhlIGZpdC5wb2ludHMgZXRjLiB0byBhIGRhdGEuZnJhbWUKCmBgYHtyfQpyZXN1bHRzIDwtYXMuZGF0YS5mcmFtZShnd3IubW9kZWwkU0RGKQpyZXN1bHRzCmBgYAoKSGEuIFNvIHRoZSBjb2VmZmljaWVudHMgYXJlIGNoYW5naW5nIGZvciBlYWNoIGNvdW5jaWwgcmVnaW9uLCBhbG9uZyB3aXRoIHRoZSBpbnRlcmNlcHRzLCBhbmQgc29tZSBvdGhlciBiaXRzIGFuZCBwaWVjZXMuIAoKSnVzdCBhcyBhIGJ5IHRoZSB3YXkuLi4gd2UgYXJlIHVzaW5nIHRoZSBAIGhlcmUgdG8gcmVmZXIgdG8gYSBzbG90IGluIHRoZSBTNCBvYmplY3QgdGhhdCB3ZSBrbm93IGlzIGEgZGF0YS5mcmFtZSAoYmVjYXVzZSBvZiB0aGUgaGVscCBwYWdlcykuIEhlcmUgaXMgYW5vdGhlciB3YXkgdG8gZm9yY2Ugb3V0IHRoZSBzYW1lIGluZm9ybWF0aW9uIHRoYXQgaXMgcHJvYmFibHkgYSBiaXQgbW9yZSBmYW1pbGlhcjoKCmBgYHtyfQpnd3IubW9kZWwkU0RGQGRhdGEKYGBgCgpFeGFjdGx5IHRoZSBzYW1lIHJpZ2h0PyBJZiB5b3Ugd2FudCB0byBmaW5kIG91dCBtb3JlIGFib3V0IFM0IGZ1bmN0aW9ucyB0aGVuIHlvdSBzaG91bGQgZ28gYW5kIGRvIENoYXB0ZXIgMiBvZiB0aGlzIERhdGEgQ2FtcCBjb3Vyc2U6IGh0dHBzOi8vY2FtcHVzLmRhdGFjYW1wLmNvbS9jb3Vyc2VzL3dvcmtpbmctd2l0aC1nZW9zcGF0aWFsLWRhdGEtaW4tci8gd2hpY2ggZ29lcyBpbnRvIHdoYXQgYHNwYCBvYmplY3RzIGFyZSAob2JqZWN0cyBvZiBjbGFzcyBTNCksIHdoYXQgdGhpcyBtZWFucywgYW5kIGhvdyB0aGV5IGJlaGF2ZSBpbiBxdWl0ZSBhIGJpdCBvZiBkZXRhaWwuIAoKSWYgd2UgZG9uJ3QgZm9yY2UgdGhlIGBzcGAgb2JqZWN0IHRvIGEgZGF0YS5mcmFtZSB0aGVuIHdlIGNhbiBjYWxsIGl0cyBuYXRpdmUgcGxvdCBmdW5jdGlvbnMKCmBgYHtyfQpzcHBsb3QoZ3dyLm1vZGVsJFNERikKYGBgCgpGYW5jeS4gV2UgY2FuIHNlZSBob3cgdGhleSBjaGFuZ2UuIEl0cyBhIGJpdCBzbG93IHRob3VnaC4gQW5kIG5vdCByZWFsbHkgYSBnb29kIGlkZWEgdG8gY29tcGFyZSB0aGVtIGxpa2UgdGhpcy4gSG93ZXZlciwgaWYgd2Ugd2FudCB0byB0aGVuIHdlIGNhbiBtYXAgb3V0IGluZGl2aWR1YWwgcmVzdWx0cyBkYXRhIGFnYWluLi4uCgpgYGB7cn0KZ3dyLm1hcCA8LSBjYmluZChPQS5DZW5zdXMsIGFzLm1hdHJpeChyZXN1bHRzKSkKdG1fc2hhcGUoZ3dyLm1hcCkgKyB0bV9maWxsKCJsb2NhbFIyIikKYGBgCgpJZiB5b3Ugd2FudCB0byBzZWUgbW9yZSBhYm91dCBob3cgdG8gcmVuZGVyIHRoZSBkaWZmZXJlbnQgYml0cyBpbiBjb21wYXJpc29uIGdyYXBocyB0aGF0IHVzZSBkaWZmZXJlbnQgc2NhbGVzICh3aGljaCBpcyB3aGVyZSB0aGUgYWJvdmUgYHBsb3RgIGNhbGwgcmVhbGx5IGZhbGxzIGRvd24pIHRoZW4gbG9vayB1cCBgZ3JpZEV4dHJhYC4gKFNlZSB0aGUgZW5kIG9mIFByYWN0aWNhbCAxMCBvZiBodHRwczovL2RhdGEuY2RyYy5hYy51ay90dXRvcmlhbC9hbi1pbnRyb2R1Y3Rpb24tdG8tc3BhdGlhbC1kYXRhLWFuYWx5c2lzLWFuZC12aXN1YWxpc2F0aW9uLWluLXIgZm9yIGEgcXVpY2sgaW50cm9kdWN0aW9uIHRvIHVzaW5nIHRoaXMgdmVyeSBoYW5keSBwYWNrYWdlLikKCiMjIyNNb3JlIGluZm9ybWF0aW9uCgoqIFByYWN0aWNhbCAxMCBvZiBodHRwczovL2RhdGEuY2RyYy5hYy51ay90dXRvcmlhbC9hbi1pbnRyb2R1Y3Rpb24tdG8tc3BhdGlhbC1kYXRhLWFuYWx5c2lzLWFuZC12aXN1YWxpc2F0aW9uLWluLXIKKiBUaGVyZSBpcyBhIHZpZ25ldHRlIG9uIEdXUjogYHZpZ25ldHRlKCJHV1IiKWAgSXQgaXMgbm90IHZlcnkgZGV0YWlsZWQgYnV0IGRvZXMgaGF2ZSBhIGxpc3Qgb2YgcmVmZXJlbmNlcyB3aGVyZSB5b3UgY2FuIGZpbmQgb3V0IG1vcmUgYWJvdXQgdGhlIHRlY2huaXF1ZS4gCiogaHR0cDovL3JzcGF0aWFsLm9yZy9hbmFseXNpcy9yc3QvNi1sb2NhbF9yZWdyZXNzaW9uLmh0bWwKKiBUaGVyZSBhcmUgbG90cyBvZiB0dXRvcmlhbHMgYW5kIG90aGVyIHJlc291cmNlcyBhcm91bmQgb24gR1dSLiBUcnkgdGhpcyBvbmU6IGh0dHBzOi8vcnB1YnMuY29tL2NocmlzYnJ1bnNkb24vMTAxMzA1LCB0aGlzIG9uZTogaHR0cHM6Ly9yc3R1ZGlvLXB1YnMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vNDQ5NzVfMDM0MmVjNDlmOTI1NDI2ZmExNmViY2RjMjgyMTAxMTguaHRtbCwgb3IgdGhlc2UgU3RhY2tFeGNoYW5nZSBwYWdlczogaHR0cHM6Ly9naXMuc3RhY2tleGNoYW5nZS5jb20vCgo=